두 파일을 한 줄씩 비교하는 방법은 무엇입니까?

두 파일을 한 줄씩 비교하는 방법은 무엇입니까?

두 개의 파일 A와 B가 있는데 거의 동일하지만 일부 줄은 다르고 일부는 엉망입니다. 이 두 파일은 systemverilog 파일이므로 이 줄에는 ; , = +등과 같은 특수 문자도 포함됩니다.

fileA의 각 줄을 반복하여 fileB에 해당 일치 항목이 있는지 확인하고 싶습니다. 비교는 규칙을 따라야 합니다

  1. 선행 및 후행 공백은 무시됩니다.
  2. 단어 사이의 여러 공백/탭은 단일 공백으로 처리될 수 있습니다.
  3. 빈 줄은 무시할 수 있습니다.

결과에는 fileA에는 있지만 fileB에는 없는 줄이 표시되어야 합니다.

시도해 보았지만 tkdiff일부 선이 엉망이 되어 많은 차이점을 보여줍니다.

답변1

휴대성이 얼마나 좋은지는 말할 수 없지만 모든 기반을 다 다루려고 노력했습니다. 귀하의 정보를 바탕으로 테스트에서 두 파일을 모두 복사하기 위해 최선을 다했습니다. sed에서 특수 문자에 문제가 있는 경우 cleanLine 함수의 두 번째 줄에서 이스케이프할 수 있습니다.

#!/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!
#++

답변2

간단한 해결책:

diff -bB fileA fileB | grep -v '^>'

-b(또는 --ignore-space-change)은 "공백량의 변화를 무시함"을 의미합니다.  -B(또는 --ignore-blank-lines)은 "모든 빈 행의 변경 사항 무시"를 의미합니다.  grep -v '>'fileA에 존재하지 않는 fileB의 행에 대한 보고서를 삭제합니다.

이것은 선행 공백을 무시하지 않지만 그렇지 않으면 원하는 것과 가깝습니다.

"B에는 존재하지만 A에는 존재하지 않는 행 diff -bB fileA fileB 재미있기도 하고, 비교를 절반만 하고 두 번 하는 대신 그냥 해보는 건 어떨까요 ?

답변3

diff -w file1 file2

공백 문자를 무시하도록 -w플래그 를 지정 합니다(이것은 대부분의 구현에서 구현되는 확장입니다).diffdiff

다음을 입력:

file1:

hello world

abc
123

this is line 2 (the last line)

file2:

        hello   world

abc
123

this is line 3 (the last line)

이 명령은

6c6
< this is line 2 (the last line)
---
> this is line 3 (the last line)

빈 줄을 무시하도록 하려면 빈 줄을 제거하여 입력 파일을 전처리하세요. 프로세스 대체(예: bash또는 ksh93) 를 이해하는 쉘을 사용하십시오 .

diff -w <( sed '/^[[:space:]]*$/d' file1 ) <( sed '/^[[:space:]]*$/d' file2 )

diff빈 줄을 무시할 수 있는 옵션이 있다면( GNU -B를 사용하는 경우 매뉴얼을 참조하세요 diff), 그것을 사용하세요. 내 것은 그런 옵션이 없습니다.

답변4

이것은 bash 스크립트입니다. 나는 인수를 검증하지 $1않았습니다 $2. 두 파일이 모두 존재하는지 확인해야 합니다. 많은 테스트를 수행하지는 않았지만 여기서는 3가지 기준이 충족된다고 생각합니다. 소스 코드는 다음과 같습니다. 스크립트는 두 파일이 동일하면 0을 반환하고 그렇지 않으면 1을 반환합니다. echo $?스크립트를 실행하면 작동합니다.

#!/bin/bash

code=0;
n=1;

dstcount=`wc -l $2 | awk '{print $1}'`

while read line
do
    #remove spaces from the beginning of line and compress tab/spaces
    src=`echo $line | tr '\t' ' ' | tr -s ' '`
    dst=`echo $(sed -n "$n"p $2) | tr '\t' ' ' | tr -s ' '`

    if [ -z "$src" ]
    then
        continue
        #advance to next line in source file
    fi

    if [ -z "$dst" ]
    then
        #advance to next in destination file
        while [ $n -le $dstcount ]
        do
            dst=`echo $(sed -n "$n"p $2) | tr '\t' ' ' | tr -s ' '`
            if [ ! -z "$dst" ]
            then
                break;
            fi

            n=`expr $n + 1`

        done

        if [ $n -gt $dstcount ]
        then
            code=1
            break
        fi

    fi

    if [ ! "$src" == "$dst" ]
    then
        code=1
        break
    fi

    n=`expr $n + 1`

done < $1

exit $code;

관련 정보