while 루프를 사용하여 두 개의 입력 파일에서 읽는 방법


27

중첩 된 while 루프의 두 입력 파일에서 한 번에 한 줄씩 읽는 방법이 있는지 알고 싶었습니다. 예를 들어, 나는 두 개의 파일이 있다고 가정 할 수 있습니다 FileAFileB.

FileA :

[jaypal:~/Temp] cat filea
this is File A line1
this is File A line2
this is File A line3

FileB :

[jaypal:~/Temp] cat fileb
this is File B line1
this is File B line2
this is File B line3

현재 샘플 스크립트 :

[jaypal:~/Temp] cat read.sh 
#!/bin/bash
while read lineA
    do echo $lineA 
    while read lineB
        do echo $lineB 
        done < fileb
done < filea

실행:

[jaypal:~/Temp] ./read.sh 
this is File A line1
this is File B line1
this is File B line2
this is File B line3
this is File A line2
this is File B line1
this is File B line2
this is File B line3
this is File A line3
this is File B line1
this is File B line2
this is File B line3

문제 및 원하는 출력 :

이것은 FileA의 각 줄에 대해 FileB를 완전히 반복합니다. continue, break, exit를 사용하려고 시도했지만 그중 어느 것도 내가 찾고있는 출력을 달성하기위한 것이 아닙니다. 스크립트가 File A에서 한 줄만 읽은 다음 FileB에서 한 줄만 읽고 루프를 종료하고 File A의 두 번째 줄과 File B의 두 번째 줄을 계속 진행하고 싶습니다. 다음 스크립트와 비슷한-

[jaypal:~/Temp] cat read1.sh 
#!/bin/bash
count=1
while read lineA
    do echo $lineA 
        lineB=`sed -n "$count"p fileb`
        echo $lineB
        count=`expr $count + 1`
done < filea

[jaypal:~/Temp] ./read1.sh 
this is File A line1
this is File B line1
this is File A line2
this is File B line2
this is File A line3
this is File B line3

while 루프로 달성 할 수 있습니까?


@codaddict 의 훌륭한 솔루션 은 다음과 같습니다. stackoverflow.com/a/4011824/4095830- >paste -d '\n' file1 file2
whoan December

답변:


32

첫 번째 파일에서 일부 문자가 발생하지 않는다는 것을 확실히 알고 있으면 붙여 넣기를 사용할 수 있습니다.

기본 구분 기호 탭을 사용한 붙여 넣기 예 :

paste file1 file2 | while IFS="$(printf '\t')" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

다음을 사용하여 붙여 넣기 예 @:

paste -d@ file1 file2 | while IFS="@" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

첫 번째 파일에서 문자가 나타나지 않는 것으로 충분합니다. 마지막 변수를 채울 때 read무시 되기 때문 입니다 IFS. 따라서 @두 번째 파일에서 발생 하더라도 분할되지 않습니다.

더 깔끔한 코드를 위해 일부 bash 기능을 사용하는 붙여 넣기 예 :

while IFS=$'\t' read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done < <(paste file1 file2)

서브 쉘 문제에서 while 루프피하기 위해 ansi c 문자열 ( $'\t') 및 프로세스 대체 ( <(...)) 와 같은 Bash 기능이 사용 되었습니다 .

두 파일 모두에서 문자가 절대 나타나지 않을 경우 파일 설명자를 사용할 수 있습니다 .

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done 3<file1 4<file2

많이 테스트되지 않았습니다. 빈 줄이 끊어 질 수 있습니다.

파일 디스크립터 번호 0, 1 및 2는 각각 stdin, stdout 및 stderr에 이미 사용됩니다. 3 이상의 파일 디스크립터는 (보통) 무료입니다. bash 매뉴얼은 "내부적으로 사용되기 때문에"9보다 큰 파일 디스크립터를 사용하지 말 것을 경고합니다.

열린 파일 디스크립터는 쉘 함수 및 외부 프로그램으로 상속됩니다. 열린 파일 디스크립터를 상속하는 함수와 프로그램은 파일 디스크립터에서 읽고 쓸 수 있습니다. 함수 또는 외부 프로그램을 호출하기 전에 필요하지 않은 모든 파일 디스크립터를 닫으십시오.

다음은 메타 작업과 분리 된 실제 작업 (인쇄)이 위와 동일한 프로그램입니다 (두 파일을 병렬로 읽는 것).

work() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  work "$f1" "$f2"
done 3<file1 4<file2

이제 우리는 작업 코드를 제어 할 수 없으며 그 이유는 무엇이든 파일 설명자 3에서 읽으려고합니다.

unknowncode() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  unknowncode "$f1" "$f2"
done 3<file1 4<file2

다음은 예제 출력입니다. 첫 번째 파일의 두 번째 줄은 루프에서 "도난"되었습니다.

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

다음은 외부 코드 (또는 그 문제에 대한 코드)를 호출하기 전에 파일 설명자를 닫는 방법입니다.

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing anycode
  anycode "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2

17

다른 파일 디스크립터 에서 두 파일을여십시오 . read내장 파일의 입력을 원하는 파일이 연결된 설명 자로 리디렉션하십시오 . bash / ksh / zsh에서는 read -u 3대신 쓸 수 있습니다 read <&3.

while IFS= read -r lineA && IFS= read -r lineB <&3; do
  echo "$lineA"; echo "$lineB"
done <fileA 3<fileB

이 스 니펫은 가장 짧은 파일이 처리되면 중지됩니다. IFS while 루프로 두 파일 읽기를 참조하십시오 .이 경우 제로 diff 결과를 얻는 방법이 있습니까? 두 파일의 끝까지 처리를 계속하려는 경우.

추가 파일 설명자를 언제 사용 하시겠습니까?를 참조하십시오 . 파일 디스크립터에 대한 추가 정보는 왜 IFS = 대신 IFS = 읽기가 자주 사용 되는가? 읽는 동안 ..`? 에 대한 설명 IFS= read -r.


파일 디스크립터의 추가 링크에 대해 @Gilles에게 감사합니다.
jaypal 싱

@Gilles 아마 당신을 오해했지만 루프 프로세스를 가장 긴 파일로 만들 수는 없었습니다 (제 경우에는 항상 $ fileA입니다). 따라서 별도의 질문으로 만들었습니다. 루프를 작성할 수있는 방법이 있습니까? diff는 입력과 출력의 차이를 느끼지 못합니까? unix.stackexchange.com/questions/26780/… 내가 얻을 수있는 가장 가까운 것은 한 줄의 차이 만 찾는 것이 었습니다.
ixtmixilix

3

쉘 스크립트가 필요하다는 것을 알고 있지만 paste명령을 살펴볼 수도 있습니다 .


감사합니다 @lutzky. paste너무 시원합니다.
jaypal 싱

2

아래 명령을 시도하십시오 :

paste -d '\n' inp1.txt inp2.txt > outfile.txt

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.