내가 만들고 있는 스크립트의 목적은 두 개의 파일 시리즈를 비교하는 것입니다. 파일 이름 자체는 두 개의 별도 파일에 한 줄에 하나씩 저장됩니다. 내 생각은 각각 파일 이름 목록에 해당하는 두 개의 루프를 갖는 것입니다 while read
. 하지만 이 두 루프를 어떻게 혼합합니까?
while read compareFile <&3; do
if [[ ! $server =~ [^[:space:]] ]] ; then #empty line exception
continue
fi
echo "Comparing file - $compareFile"
if diff "$compareFile" _(other file from loop?_) >/dev/null ; then
echo Same
else
echo Different
fi
done 3</infanass/dev/admin/filestoCompare.txt
두 개의 while read 루프를 통해 두 개의 다른 목록에 있는 파일을 동시에 비교할 수 있어야 합니다. 이것이 가능합니까?
답변1
두 개의 루프가 필요하지 않습니다. 하나의 루프에서 두 파일을 모두 읽으면 됩니다.
while read compareFile1 <&3 && read compareFile2 <&4; do
if [[ ! $server =~ [^[:space:]] ]] ; then #empty line exception
continue
fi
echo "Comparing file - $compareFile"
if diff "$compareFile1" "$compareFile2" >/dev/null ; then
echo Same
else
echo Different
fi
done 3</infanass/dev/admin/filestoCompare.txt 4<other_file
답변2
방법 1: 알고 있는 정보를 활용하세요
파일을 반복하는 방법을 이미 알고 있으므로 파일을 결합한 다음 결합된 파일을 처리할 수 있습니다. 주문하다paste
두 파일을 한 줄씩 연결합니다. 두 파일의 줄 사이에 탭 문자를 배치하므로 이 솔루션에서는 파일 이름에 탭 문자가 없다고 가정합니다. (구분자는 변경할 수 있으나, 파일명에 존재하지 않는 문자를 반드시 찾아내야 합니다.)
paste -- "$list1.txt" "list2.txt" |
while IFS=$'\t' read -r file1 file2 rest; do
diff -q -- "$file1" "$file2"
case $? in
0) status='same';;
1) status='different';;
*) status='ERROR';;
esac
echo "$status $file1 $file2"
done
빈 줄을 건너뛰려면 paste
한 파일의 빈 줄을 다른 파일의 비어 있지 않은 줄과 일치시킬 수 있으므로 각 파일에서 개별적으로 이 작업을 수행해야 합니다. 이를 사용하여 grep
비어 있지 않은 줄을 필터링할 수 있습니다.
paste -- <(grep '[^[:space:]]' "$list1.txt") <(grep '[^[:space:]]' "list2.txt") |
while IFS=$'\t' read -r file1 file2 rest; do
…
두 파일의 길이가 다른 경우에는 빈 파일을 얻게 됩니다 $file2
(어떤 목록이 먼저 끝나든 관계 없음).
방법 2: 두 파일 반복
while 루프 조건에서는 임의로 복잡한 명령을 입력할 수 있습니다. 넣으면 read file1 <&3 && read file2 <&4
두 파일 모두 읽을 줄이 있는 한, 즉 하나의 파일을 읽을 때까지 루프가 실행됩니다.
while read -u 3 -r file1 && read -u 4 -r file2; do
…
done 3<list1..txt 4<list2.txt
빈 줄을 건너뛰려면 두 파일 모두에서 독립적으로 수행해야 하기 때문에 좀 더 복잡합니다. 간단한 접근 방식은 문제를 두 부분으로 나누는 것입니다. 즉, 파일에서 빈 줄을 건너뛰는 것과 비어 있지 않은 줄을 처리하는 것입니다. 빈 줄을 건너뛰는 한 가지 방법은 grep
위와 같이 하는 것입니다. <
리디렉션 연산자와 명령 대체를 시작하는 연산자 <(
사이에 필요한 공백을 기록해 두십시오 .
while read -u 3 -r file1 && read -u 4 -r file2; do
…
done 3< <(grep '[^[:space:]]' "$list1.txt") 4< <(grep '[^[:space:]]' "list2.txt")
read
또 다른 접근 방식은 유사하게 동작하지만 빈 줄을 건너뛰는 함수를 작성하는 것입니다 . 이 함수 read
는 루프에서 호출하여 작동합니다. 함수일 필요는 없지만 함수는 코드를 구성하고 코드를 두 번 호출해야 하기 때문에 이를 수행하는 가장 좋은 방법입니다. 함수에서 는 value 라는 변수의 값을 계산하는 ${!#}
bash 구문의 인스턴스입니다 . 여기서 변수는 위치 인수 수 와 마지막 위치 인수를 포함하는 특수 변수입니다.${!VARIABLE}
VARIABLE
#
${!#}
function read_nonblank {
while read "$@" &&
[[ ${!#} !~ [^[:space:]] ]]
do :; done
}
while read_nonblank -u 3 -r file1 && read_nonblank -u 4 -r file2; do
…
done 3<list1..txt 4<list2.txt
답변3
한 가지 방법 read -ra
은 2개의 열이 있고 각각 파일 이름이 있다고 read
가정하면 두 열을 모두 읽고 배열에 할당하여 루프를 통해 인덱스 0이 사용되도록 하는 것입니다. 첫 번째 파일과 인덱스 1은 두 번째 파일이 됩니다 .filestoCompare.txt
read -ra
compareFile
while
예
filestoCompare.txt
다음 내용이 포함된 파일이 있다고 가정해 보겠습니다 .
file1 file2
file3 file4
file5 file6
파일을 찾아보는 명령은 다음과 같습니다.
$ while read -ra a ; do printf "%s\t%s\n" ${a[0]} ${a[1]}; done < filestoCompare.txt
file1 file2
file3 file4
file5 file6
두 파일이 실제로 별도의 파일인 경우 예를 들면 다음과 같습니다.
#list1
file1
file2
file3
#list2
file4
file5
file6
다음과 같은 명령을 통해 서로 연결할 수 있습니다 paste
.
$ paste list1 list2 > list1and2
목록 1과 2의 내용은 다음과 같습니다.
$ cat list1and2
file1 file4
file2 file5
file3 file6