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

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

중첩된 while 루프에서 두 개의 입력 파일을 동시에 읽을 수 있는 방법이 있는지 궁금합니다. 예를 들어 두 개의 파일 FileAFileB.

파일 A:

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

파일 B:

[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가 완전히 반복됩니다. 계속, 중단, 종료를 사용해 보았지만 그 중 어느 것도 내가 원하는 결과를 얻지 못했습니다. 스크립트가 파일 A에서 한 줄만 읽은 다음 파일 B에서 한 줄을 읽은 다음 루프를 종료하고 파일 A의 두 번째 줄과 파일 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 루프를 사용하여 이를 달성할 수 있습니까?

답변1

첫 번째 파일에 특정 문자가 절대 나타나지 않도록 보장할 수 있다면 붙여넣기를 사용할 수 있습니다.

예를 들어, 이런 일은 절대 일어나지 않을 것이라고 확신합니다 @.

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)

사용된 Bash 함수:ANSI C 문자열( $'\t') 그리고프로세스 교체( <(...)) 도착하다서브셸에서 while 루프 문제 방지.

두 파일 모두에 어떤 문자도 나타나지 않을지 확실하지 않은 경우 두 개의 파일을 사용할 수 있습니다.파일 설명자.

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

답변2

이 두 파일을 다른 위치에서 엽니다.파일 설명자. 내장된 파일의 입력을 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 루프로 읽는 중 - 이 경우 차이가 없는 결과를 얻을 수 있는 방법이 있습니까?두 파일이 끝날 때까지 계속 처리하려는 경우.

당신은 또한 볼 수 있습니다추가 파일 설명자는 언제 사용됩니까?파일 설명자에 대한 추가 정보 및"IFS=;" 대신 "IFS= 읽기"가 자주 사용되는 이유는 무엇입니까?에 대한 설명 IFS= read -r.

답변3

다음 명령을 시도해 보십시오:

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

답변4

또는 bash의 mapfile 명령을 사용하여 파일을 배열 변수에 넣고 파일의 각 줄을 array[line_of_file_index]에 바인딩할 수 있다고 가정합니다. 그러나 Bash3 이상이나 Bash4에서만 작동하는지 확실하지 않습니다.

http://wiki.bash-hackers.org/commands/builtin/mapfile

관련 정보