두 개의 파일 A와 B가 있는데 거의 동일하지만 일부 줄은 다르고 일부는 엉망입니다. 이 두 파일은 systemverilog 파일이므로 이 줄에는 ; , = +
등과 같은 특수 문자도 포함됩니다.
fileA의 각 줄을 반복하여 fileB에 해당 일치 항목이 있는지 확인하고 싶습니다. 비교는 규칙을 따라야 합니다
- 선행 및 후행 공백은 무시됩니다.
- 단어 사이의 여러 공백/탭은 단일 공백으로 처리될 수 있습니다.
- 빈 줄은 무시할 수 있습니다.
결과에는 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
플래그 를 지정 합니다(이것은 대부분의 구현에서 구현되는 확장입니다).diff
diff
다음을 입력:
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;