두 파일의 줄을 통한 병렬 루프 [닫기]

두 파일의 줄을 통한 병렬 루프 [닫기]

내가 만들고 있는 스크립트의 목적은 두 개의 파일 시리즈를 비교하는 것입니다. 파일 이름 자체는 두 개의 별도 파일에 한 줄에 하나씩 저장됩니다. 내 생각은 각각 파일 이름 목록에 해당하는 두 개의 루프를 갖는 것입니다 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.txtread -racompareFilewhile

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

관련 정보