2つのファイルを1行ずつ比較する方法は?

2つのファイルを1行ずつ比較する方法は?

2つのファイルAとBがありますが、ほぼ同じですが、一部の行は異なり、一部は混乱しています。これら2つのファイルはsystemverilogファイルなので、この行にはなど; , = +の特殊文字も含まれています。

fileAの各行を繰り返して、fileBに対応する一致があるかどうかを確認したいと思います。比較は規則に従うべきです

  1. 先行および末尾のスペースは無視されます。
  2. 単語間の複数のスペース/タブを単一のスペースとして扱うことができます。
  3. 空行は無視できます。

結果には fileA にはあるが fileB にはない行を表示する必要があります。

試してみましたが、tkdiff一部の線が混乱して多くの違いを示しています。

ベストアンサー1

携帯性がどれほど良いかは言えませんが、すべての基盤に対処しようとしました。あなたの情報に基づいて、テストから両方のファイルをコピーするために最善を尽くしました。 sedで特殊文字に問題がある場合は、cleanLine関数の2行目からエスケープできます。

#!/bin/bash

# compare two files and return lines in
# first file that are missing in second file

ProgName=${0##*/}
Pid=$$
CHK_FILE="$1"
REF_FILE="$2"
D_BUG="$3"
TMP_FILE="/tmp/REF_${Pid}.tmp"
declare -a MISSING='()'
m=0

scriptUsage() {
cat <<ENDUSE

    $ProgName  <file_to_check> <reference_file> [-d|--debug]

    Lines in 'file_to_check' not present in 'reference_file'
      are printed to standard output.

    file_to_check:     File being checked
    reference_file:    File to be checked against
    -d|--debug:        Run script in debug mode (Optional)
    -h|--help:         Print this help message

ENDUSE
}

# delete temp file on any exit
trap 'rm $TMP_FILE > /dev/null 2>&1' EXIT


#-- check args
  [[ $CHK_FILE == "-h" || $CHK_FILE == "--help" ]] && { scriptUsage; exit 0; }
  [[ -n $CHK_FILE && -n $REF_FILE ]] || { >&2 echo "Not enough arguments!"; scriptUsage; exit 1; }
  [[ $D_BUG == "-d" || $D_BUG == "--debug" ]] && set -x
  [[ -s $CHK_FILE ]] || { >&2 echo "File $CHK_FILE not found"; exit 1; }
  [[ -s $REF_FILE ]] || { >&2 echo "File $REF_FILE not found"; exit 1; }
#--


#== edit temp file to 3 match comparison rules
  # copy ref file to temp for editing
  cp "$REF_FILE" $TMP_FILE || { >&2 echo "Unable to create temporary file"; exit 1; }
  # rule 3 - ignore empty lines
  sed -i '/^\s*$/d' $TMP_FILE
  # rule 1 - ignore begin/end of line spaces
  sed -i 's/^[[:space:]][[:space:]]*//;s/[[:space:]][[:space:]]*$//' $TMP_FILE
  # rule 2 - multi space/tab as single space
  sed -i 's/[[:space:]][[:space:]]*/ /g' $TMP_FILE
#==


# function to clean LINE to match 3 rules
# & escape '/' and '.' for later sed command
cleanLine() {
  var=$(echo "$1" | sed 's/^[[:space:]][[:space:]]*//;s/[[:space:]][[:space:]]*$//;s/[[:space:]][[:space:]]*/ /g')
  echo $var | sed 's/\//\\\//g;s/\./\\\./g'
}


### parse check file
while IFS='' read -r LINE || [[ -n $LINE ]]
  do
    if [[ -z $LINE ]]
      then
        continue
      else
        CLN_LINE=$(cleanLine "$LINE")
        FOUND=$(sed -n "/$CLN_LINE/{p;q}" $TMP_FILE)
        [[ -z $FOUND ]] && MISSING[$m]="$LINE" && ((m++))
        FOUND=""
    fi
done < "$CHK_FILE"
###


#++ print missing line(s) (if any)
  if (( $m > 0 ))
    then
      printf "\n  Missing line(s) found:\n"
      #*SEE BELOW ON THIS
      for (( p=0; $p<$m; p++ ))
        do
          printf "    %s\n" "${MISSING[$p]}"
      done
      echo
    else
      printf "\n  **No missing lines found**\n\n"
  fi
#* using 'for p in ${MISSING[@]}' causes:
#* "SPACED LINES" to become:
#* "SPACED"
#* "LINES" when printed to stdout!
#++

おすすめ記事