Bash의 텍스트 파일에서 여러 줄 읽기

Bash의 텍스트 파일에서 여러 줄 읽기

쉘 스크립트를 작성할 때 제가 하는 대부분의 작업은 Python, Matlab 등의 다른 모듈에서 I/O를 래핑하는 것입니다. 이를 위해 나는 일반적으로 입력/출력 경로가 있는 텍스트 파일이나 유사한 성격의 파일을 사용합니다. 나는 사용할 수 있는 파일에서 한 줄을 읽는 방법을 알고 있습니다.

for file in $(cat $1);
do
    code using $file
done

하지만 두 파일의 동일한 줄을 사용하여 작업을 수행하려면 어떻게 해야 합니까? Java와 유사합니다.

while((line1 = file1.readLine()) != null) {
    line2 = file2.readLine();
    //do something with both lines...
}

Bash에서 이를 수행하는 표준 방법은 무엇입니까?

답변1

exec 3<file1
exec 4<file2
while read line1 <&3 && read line2 <&4
do
        echo "line1=$line1 and line2=$line2"
done
exec 3<&-
exec 4<&-

논의하다

  • 위에서는 입력 줄에서 선행 및 후행 공백이 제거되었습니다. 이 공간을 유지하려면 read …다음으로 바꾸십시오.IFS= read …

  • 위에서 입력의 백슬래시는 이스케이프 문자로 해석됩니다. 이 작업을 수행하지 않으려면 다음 read …으로 교체하세요.read -r …

  • read line1 <&3line1파일 설명자 3에서 읽습니다. 이는 다음과 같이 동등하게 쓸 수도 있습니다 read -u3 line1.

  • 이와 같은 진술 에는 for file in $(cat $1);알아야 할 몇 가지 문제가 있습니다. 쉘은 파일 내용에 토큰화된 경로 이름 확장을 적용하므로 이를 예상하지 않는 한 다양한 오류가 발생할 수 있습니다.

선택하다

while read line1 <&3 && read line2 <&4
do
        echo "line1=$line1 and line2=$line2"
done 3<file1 4<file2

답변2

파일의 행을 반복하려면 다음을 수행하십시오.

while IFS= read -r line; do
  echo "read $line"
done <input-file

여러 파일을 반복하려면 다른 파일 설명자에서 해당 파일을 엽니다(참조추가 파일 설명자는 언제 사용됩니까?).

while IFS= read -r line1 <&8 || IFS= read -r line2 <&9; do
  echo "read '$line1' from file 1 and '$line2' from file 2"
done 8<input-file1 9<input-file2

가장 긴 파일과 일치하도록 빈 줄로 read <&8 || read <&9가장 짧은 파일을 완성하십시오 . 두 파일 중 하나의 끝에 도달했을 때 즉시 종료하려면 &&대신 을 사용하십시오 ||. 모든 경우를 감지하려면 개별적으로 반환 코드를 확인하십시오.

{
  while
    IFS= read -r line1 <&8; empty1=$?
    IFS= read -r line2 <&9; empty2=$?
    [ "$empty1" -ne 0 ] && [ "$empty2" -ne 0 ]
  do
    echo "read '$line1' from file 1 and '$line2' from file 2"
  done
  if [ "$empty1" -ne 0 ]; then
    echo "Finishing processing file 1"
  fi
  if [ "$empty2" -ne 0 ]; then
    echo "Finishing processing file 2"
  fi
} 8<input-file1 9<input-file2

또는 두 파일을 함께 연결할 수 있습니다. 이것paste이를 위해서는 명령이 편리합니다. 기본적으로 탭별로 줄을 구분하고( -d다른 구분 기호를 선택하려면 전달) 빈 줄로 파일을 완성합니다. 파일에 탭 문자가 포함되어 있지 않으면 입력 줄이 명확하게 구분됩니다.

tab=$(printf \\t)
paste input-file1 input-file2 |
while IFS=$tab read -r line1 line2; do … done

셸은 텍스트 처리 속도가 그리 빠르지 않습니다. 중대형 입력에는 보다 전문화된 도구가 가장 적합합니다. 전처리를 사용하면 paste후처리를 위해 두 파일을 쉽게 압축할 수 있습니다. 행을 읽을 때 더 많은 제어가 필요한 경우 awk는 해당 명령을 사용하여 이를 수행 할 수 있습니다 getline(셸의 ​​와 유사 ).read

관련 정보