그래서 기본적으로 내가하고 싶은 것은 두 파일을 열 2별로 비교하는 것입니다. 어떻게 이것을 할 수 있습니까?
File_1.txt :
User1 US
User2 US
User3 US
File_2.txt :
User1 US
User2 US
User3 NG
결과물 파일:
User3 has changed
그래서 기본적으로 내가하고 싶은 것은 두 파일을 열 2별로 비교하는 것입니다. 어떻게 이것을 할 수 있습니까?
File_1.txt :
User1 US
User2 US
User3 US
File_2.txt :
User1 US
User2 US
User3 NG
결과물 파일:
User3 has changed
답변:
diff
명령을 살펴보십시오 . 좋은 도구이며 man diff
터미널 에 입력하여 모든 정보를 읽을 수 있습니다 .
당신이하고 싶은 명령 diff File_1.txt File_2.txt
은 둘 사이의 차이를 출력하고 다음과 같이 보일 것입니다 :
세 번째 명령의 출력을 읽는 것에 대한 간단한 참고 사항 : '화살표'( <
및 >
)는 왼쪽 파일 ( <
) 대 오른쪽 파일 ( >
) 에있는 줄 값을 나타 냅니다. 왼쪽 파일은 입력 한 값입니다. 이 경우에는 명령 행에서 먼저File_1.txt
또한 네 번째 명령은 diff ... | tee Output_File
결과를에서 diff
로 파이프하여 tee
출력을 파일로 저장하므로 나중에 콘솔에서 모든 것을 보지 않으려면 나중에 저장할 수 있습니다.
diff file1 file2 -s
.. 예를 들면 다음과 같습니다. imgur.com/ShrQx9x
또는 Meld Diff를 사용할 수 있습니다
Meld는 파일, 디렉토리 및 버전 제어 프로젝트를 비교하는 데 도움이됩니다. 파일과 디렉토리의 양방향 및 3 방향 비교를 제공하며 많은 인기있는 버전 제어 시스템을 지원합니다.
다음을 실행하여 설치하십시오.
sudo apt-get install meld
귀하의 예 :
디렉토리 비교 :
텍스트가 가득한 예 :
다음 명령을 사용할 수 있습니다 cmp
.
cmp -b "File_1.txt" "File_2.txt"
출력은
a b differ: byte 25, line 3 is 125 U 116 N
cmp
diff
리턴 코드가 원하는 것보다 훨씬 빠릅니다 .
Litteraly가 질문 (file1, file2, "변경된"메시지가있는 outputfile)을 고수하면 아래 스크립트가 작동합니다.
스크립트를 빈 파일에 복사하고로 저장 compare.py
하고 실행 파일로 만든 후 다음 명령으로 실행하십시오.
/path/to/compare.py <file1> <file2> <outputfile>
스크립트 :
#!/usr/bin/env python
import sys
file1 = sys.argv[1]; file2 = sys.argv[2]; outfile = sys.argv[3]
def readfile(file):
with open(file) as compare:
return [item.replace("\n", "").split(" ") for item in compare.readlines()]
data1 = readfile(file1); data2 = readfile(file2)
mismatch = [item[0] for item in data1 if not item in data2]
with open(outfile, "wt") as out:
for line in mismatch:
out.write(line+" has changed"+"\n")
몇 줄을 추가하면 출력 파일이 정의되어 있는지 여부에 따라 출력 파일 또는 터미널로 인쇄 할 수 있습니다.
파일로 인쇄하려면
/path/to/compare.py <file1> <file2> <outputfile>
터미널 창에 인쇄하려면
/path/to/compare.py <file1> <file2>
스크립트 :
#!/usr/bin/env python
import sys
file1 = sys.argv[1]; file2 = sys.argv[2]
try:
outfile = sys.argv[3]
except IndexError:
outfile = None
def readfile(file):
with open(file) as compare:
return [item.replace("\n", "").split(" ") for item in compare.readlines()]
data1 = readfile(file1); data2 = readfile(file2)
mismatch = [item[0] for item in data1 if not item in data2]
if outfile != None:
with open(outfile, "wt") as out:
for line in mismatch:
out.write(line+" has changed"+"\n")
else:
for line in mismatch:
print line+" has changed"
쉬운 방법은을 사용 colordiff
하는 것 diff
입니다. 이것은 diff를 읽는 데 매우 도움이됩니다. 예를 사용하면
$ colordiff -u File_1.txt File_2.txt
--- File_1.txt 2016-12-24 17:59:17.409490554 -0500
+++ File_2.txt 2016-12-24 18:00:06.666719659 -0500
@@ -1,3 +1,3 @@
User1 US
User2 US
-User3 US
+User3 NG
여기서 u
옵션은 통합 된 diff를 제공합니다. 이것이 색상 화 된 diff의 모습입니다 :
colordiff
를 실행하여 설치하십시오 sudo apt-get install colordiff
.
파일의 어떤 부분이 다른지 알 필요가없는 경우 파일의 체크섬을 사용할 수 있습니다. 사용하여 해당 작업을 수행하는 여러 가지 방법있다 md5sum
거나 sha256sum
. 기본적으로 각각은 파일 내용이 해시되는 문자열을 출력합니다. 두 파일이 동일하면 해시도 동일합니다. 우분투 설치 ISO 이미지와 같은 소프트웨어를 다운로드 할 때 자주 사용됩니다. 다운로드 한 콘텐츠의 무결성을 확인하는 데 자주 사용됩니다.
두 개의 파일을 인수로 제공 할 수있는 스크립트를 아래에서 고려하십시오. 그러면 파일이 동일한 지 여부를 알려줍니다.
#!/bin/bash
# Check if both files exist
if ! [ -e "$1" ];
then
printf "%s doesn't exist\n" "$1"
exit 2
elif ! [ -e "$2" ]
then
printf "%s doesn't exist\n" "$2"
exit 2
fi
# Get checksums of eithe file
file1_sha=$( sha256sum "$1" | awk '{print $1}')
file2_sha=$( sha256sum "$2" | awk '{print $1}')
# Compare the checksums
if [ "x$file1_sha" = "x$file2_sha" ]
then
printf "Files %s and %s are the same\n" "$1" "$2"
exit 0
else
printf "Files %s and %s are different\n" "$1" "$2"
exit 1
fi
샘플 실행 :
$ ./compare_files.sh /etc/passwd ./passwd_copy.txt
Files /etc/passwd and ./passwd_copy.txt are the same
$ echo $?
0
$ ./compare_files.sh /etc/passwd /etc/default/grub
Files /etc/passwd and /etc/default/grub are different
$ echo $?
1
또한 comm
두 개의 정렬 된 파일을 비교하고 3 개의 열로 출력합니다. 파일 # 1에 고유 한 항목에 대해서는 열 1, 파일 # 2에 고유 한 항목에 대해서는 열 2, 두 파일에있는 항목에 대해서는 열 3이 있습니다.
열을 억제하기 위해 스위치 -1, -2 및 -3을 사용할 수 있습니다. -3을 사용하면 다른 줄이 표시됩니다.
아래 명령의 스크린 샷을 볼 수 있습니다.
하나의 요구 사항 만 있습니다. 파일을 올바르게 비교하려면 파일을 정렬해야합니다. sort
그 목적으로 명령을 사용할 수 있습니다. Bellow는 파일을 정렬 한 다음 비교하는 또 다른 스크린 샷입니다. 왼쪽에서 시작하여 줄은 File_1에만, 2 열에서 시작하는 줄은 File_2에만 속합니다
형식에서 두 파일의 이름 / 값 쌍을 비교합니다 name value\n
. 는 기록 name
에 Output_file
변경 한 경우. 연관 배열 에는 bash v4 +가 필요합니다 .
$ ./colcmp.sh File_1.txt File_2.txt
User3 changed from 'US' to 'NG'
no change: User1,User2
$ cat Output_File
User3 has changed
cmp -s "$1" "$2"
case "$?" in
0)
echo "" > Output_File
echo "files are identical"
;;
1)
echo "" > Output_File
cp "$1" ~/.colcmp.array1.tmp.sh
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array1.tmp.sh
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.array1.tmp.sh
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A1\\[\\1\\]=\"\\2\"/" ~/.colcmp.array1.tmp.sh
chmod 755 ~/.colcmp.array1.tmp.sh
declare -A A1
source ~/.colcmp.array1.tmp.sh
cp "$2" ~/.colcmp.array2.tmp.sh
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A2\\[\\1\\]=\"\\2\"/" ~/.colcmp.array2.tmp.sh
chmod 755 ~/.colcmp.array2.tmp.sh
declare -A A2
source ~/.colcmp.array2.tmp.sh
USERSWHODIDNOTCHANGE=
for i in "${!A1[@]}"; do
if [ "${A2[$i]+x}" = "" ]; then
echo "$i was removed"
echo "$i has changed" > Output_File
fi
done
for i in "${!A2[@]}"; do
if [ "${A1[$i]+x}" = "" ]; then
echo "$i was added as '${A2[$i]}'"
echo "$i has changed" > Output_File
elif [ "${A1[$i]}" != "${A2[$i]}" ]; then
echo "$i changed from '${A1[$i]}' to '${A2[$i]}'"
echo "$i has changed" > Output_File
else
if [ x$USERSWHODIDNOTCHANGE != x ]; then
USERSWHODIDNOTCHANGE=",$USERSWHODIDNOTCHANGE"
fi
USERSWHODIDNOTCHANGE="$i$USERSWHODIDNOTCHANGE"
fi
done
if [ x$USERSWHODIDNOTCHANGE != x ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
;;
*)
echo "error: file not found, access denied, etc..."
echo "usage: ./colcmp.sh File_1.txt File_2.txt"
;;
esac
내가 아는 한 코드의 의미와 의미 편집 및 제안을 환영합니다.
cmp -s "$1" "$2"
case "$?" in
0)
# match
;;
1)
# compare
;;
*)
# error
;;
esac
내가 사용하도록 선택한 경우 .. ESAC의 evalute에 문을 $? $ 의 가치 때문에 ? 테스트 ([)를 포함한 모든 명령 후에 변경됩니다 .
또는 변수를 사용하여 $ 의 값을 보유 할 수 있습니까? :
cmp -s "$1" "$2"
CMPRESULT=$?
if [ $CMPRESULT -eq 0 ]; then
# match
elif [ $CMPRESULT -eq 1 ]; then
# compare
else
# error
fi
위의 경우는 성명서와 동일합니다. 내가 더 좋아하는 IDK.
echo "" > Output_File
위는 출력 파일을 지우므로 사용자가 변경되지 않은 경우 출력 파일이 비어 있습니다.
나는 내에서이 작업을 수행 할 경우 있도록 문 OUTPUT_FILE이 오류에 변경되지 않습니다.
cp "$1" ~/.colcmp.arrays.tmp.sh
위에서 File_1.txt 를 현재 사용자의 홈 디렉토리로 복사 합니다.
예를 들어, 현재 사용자가 john 인 경우 위의 내용은 cp "File_1.txt"/home/john/.colcmp.arrays.tmp.sh와 같습니다.
기본적으로 저는 편집증입니다. 변수 할당의 일부로 스크립트에서 실행할 때 이러한 문자가 특별한 의미를 갖거나 외부 프로그램을 실행할 수 있음을 알고 있습니다.
내가 모르는 것은 bash에 대해 얼마나 많이 모른다 는 것입니다. 다른 문자가 특별한 의미를 갖는지 모르겠지만 백 슬래시로 모든 문자를 이스케이프 처리하고 싶습니다.
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array1.tmp.sh
sed 는 정규 표현식 패턴 일치 보다 훨씬 더 많은 작업을 수행 할 수 있습니다. 스크립트 패턴 "s / (find) / (replace) /"는 구체적으로 패턴 일치를 수행합니다.
"s / (찾기) / (바꾸기) / (modifiers)"
영어 : 문장 부호 또는 특수 문자를 캡처 그룹 1 (\\ 1)로 캡처
영어로 : 모든 특수 문자 앞에 백 슬래시를 붙이십시오
영어로 : 같은 줄에 둘 이상의 일치하는 것이 있으면 모두 바꾸십시오.
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.arrays.tmp.sh
위의 정규 표현식을 사용하여 ~ / .colcmp.arrays.tmp.sh 의 모든 줄 앞에 bash 주석 문자 ( # )를 붙 입니다 . 나중에 내가 실행하려는 때문에 이렇게 ~ / .colcmp.arrays.tmp.sh을 사용하여 소스 내가 확신 전체 형식 모르기 때문에 명령을하고 File_1.txt .
실수로 임의의 코드를 실행하고 싶지 않습니다. 나는 아무도 생각하지 않습니다.
"s / (찾기) / (바꾸기) /"
영어로 : 각 줄을 캡처 그룹 1 (\\ 1)로 캡처
영어로 : 각 줄을 파운드 기호로 바꾸고 그 뒤에 바뀐 줄을 바꿉니다.
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A1\\[\\1\\]=\"\\2\"/" ~/.colcmp.arrays.tmp.sh
위는이 스크립트의 핵심입니다.
#User1 US
A1[User1]="US"
A2[User1]="US"
(두 번째 파일의 경우)"s / (찾기) / (바꾸기) /"
영어로:
캡처 그룹 2로 나머지 라인을 캡처
(대체) = A1 \\ [\\ 1 \\] = \ "\\ 2 \"
A1[
배열에서 배열 할당을 시작하는 리터럴 문자A1
]="
]
= 가까운 배열 할당, 예 : A1[
User1 ]="
US"
=
= 대입 연산자 예 : 변수 = 값"
= 공백을 캡처하는 인용 값 ... ... 지금 생각하지만, 위의 코드를 백 슬래시 공백 문자로 백 슬래시하는 것이 더 쉬울 것입니다.영어로 : 형식의 각 줄을 형식 #name value
의 배열 할당 연산자로 바꿉니다.A1[name]="value"
chmod 755 ~/.colcmp.arrays.tmp.sh
위에서 chmod 를 사용하여 배열 스크립트 파일을 실행 가능하게 만듭니다.
이것이 필요한지 확실하지 않습니다.
declare -A A1
대문자 -A는 선언 된 변수가 연관 배열 임을 나타냅니다 .
이것이 스크립트에 bash v4 이상이 필요한 이유입니다.
source ~/.colcmp.arrays.tmp.sh
우리는 이미 :
User value
라인에 A1[User]="value"
,위 의 스크립트를 현재 쉘에서 실행하기 위해 소스를 만듭니다. 이를 통해 스크립트에서 설정 한 변수 값을 유지할 수 있습니다. 스크립트를 직접 실행하면 새 셸이 생성되고 새 셸이 종료 될 때 변수 값이 손실되거나 적어도 내 이해입니다.
cp "$2" ~/.colcmp.array2.tmp.sh
sed -i -E "s/([^A-Za-z0-9 ])/\\\\\\1/g" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^(.*)$/#\\1/" ~/.colcmp.array2.tmp.sh
sed -i -E "s/^#\\s*(\\S+)\\s+(\\S.*?)\\s*\$/A2\\[\\1\\]=\"\\2\"/" ~/.colcmp.array2.tmp.sh
chmod 755 ~/.colcmp.array2.tmp.sh
declare -A A2
source ~/.colcmp.array2.tmp.sh
우리는 $ 1 과 A1 에 대해 $ 2 와 A2에 대해하는 것과 같은 일을 합니다. 실제로 함수 여야합니다. 나는이 시점 에서이 스크립트가 충분히 혼란스럽고 작동한다고 생각하므로 수정하지 않을 것입니다.
for i in "${!A1[@]}"; do
# check for users removed
done
위의 연관 배열 키를 통한 루프
if [ "${A2[$i]+x}" = "" ]; then
위에서 변수 대체를 사용하여 설정되지 않은 값과 길이가 0 인 문자열로 명시 적으로 설정된 변수 간의 차이를 감지합니다.
분명히 변수가 설정되었는지 확인 하는 많은 방법이 있습니다 . 나는 가장 많은 표를 얻은 사람을 선택했다.
echo "$i has changed" > Output_File
위에서 $ i 사용자 를 Output_File에 추가합니다.
USERSWHODIDNOTCHANGE=
위는 변수를 지우므로 변경되지 않은 사용자를 추적 할 수 있습니다.
for i in "${!A2[@]}"; do
# detect users added, changed and not changed
done
위의 연관 배열 키를 통한 루프
if ! [ "${A1[$i]+x}" != "" ]; then
위에서 변수 대체를 사용 하여 변수가 설정되었는지 확인합니다 .
echo "$i was added as '${A2[$i]}'"
$ i 는 배열 키 (사용자 이름) 이므로 $ A2 [$ i]는 File_2.txt 에서 현재 사용자와 연관된 값을 반환해야합니다 .
예를 들어 $ i 가 User1 인 경우 위의 $ {A2 [User1]}
echo "$i has changed" > Output_File
위에서 $ i 사용자 를 Output_File에 추가합니다.
elif [ "${A1[$i]}" != "${A2[$i]}" ]; then
$ i 는 배열 키 (사용자 이름) 이므로 $ A1 [$ i]는 File_1.txt 에서 현재 사용자와 연관된 값을 반환 하고 $ A2 [$ i]는 File_2.txt 에서 값을 반환해야합니다 .
위의 두 파일에서 사용자 $ i 의 관련 값을 비교 합니다.
echo "$i has changed" > Output_File
위에서 $ i 사용자 를 Output_File에 추가합니다.
if [ x$USERSWHODIDNOTCHANGE != x ]; then
USERSWHODIDNOTCHANGE=",$USERSWHODIDNOTCHANGE"
fi
USERSWHODIDNOTCHANGE="$i$USERSWHODIDNOTCHANGE"
위는 변경되지 않은 쉼표로 구분 된 사용자 목록을 만듭니다. 목록에 공백이 없거나 다음 검사를 인용해야합니다.
if [ x$USERSWHODIDNOTCHANGE != x ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
위의 값보고 $ USERSWHODIDNOTCHANGE을 하지만에 값이있는 경우에만 $ USERSWHODIDNOTCHANGE . $ USERSWHODIDNOTCHANGE 가 작성되는 방식 에는 공백이 포함될 수 없습니다. 공백이 필요하면 위와 같이 다시 쓸 수 있습니다.
if [ "$USERSWHODIDNOTCHANGE" != "" ]; then
echo "no change: $USERSWHODIDNOTCHANGE"
fi
diff "File_1.txt" "File_2.txt"