Linux Bash 스크립트에서 파일을 한 줄씩 처리하는 방법

0
746

Linux 컴퓨터 시스템의 터미널 창.
Fatmawati Achmad Zaenuri / Shutterstock

셸 스크립트에서 Linux 텍스트 파일의 내용을 한 줄씩 읽는 것은 매우 쉽습니다. 안전한 방법으로 수행하는 방법은 다음과 같습니다.

파일, 텍스트 및 숙어

각 프로그래밍 언어에는 일련의 관용구가 있습니다. 이것은 일련의 일반적인 작업을 수행하는 표준적이고 간단한 방법입니다. 프로그래머가 작업하는 언어의 기능 중 하나를 사용하는 기본 또는 기본 방법입니다. 그들은 프로그래머의 정신적 청사진 툴킷의 일부가됩니다.

파일에서 데이터 읽기, 루프 작업, 두 변수의 값 교체와 같은 작업이 좋은 예입니다. 프로그래머는 일반 또는 바닐라 방식으로 목적을 달성하는 방법을 적어도 한 가지 알고있을 것입니다. 아마도 그것은 당면한 요구 사항으로 충분할 것입니다. 또는 코드를 더 효율적으로 만들거나 개발중인 특정 솔루션에 적용 할 수 있습니다. 그러나 빌딩 블록 관용구를 손끝으로 사용하는 것은 좋은 출발점입니다.

한 언어로 된 관용구를 알고 이해하면 새로운 프로그래밍 언어를 쉽게 선택할 수 있습니다. 하나의 언어로 사물이 구성되는 방식을 알고 다른 언어에서 동등한 또는 가장 가까운 것을 찾는 것은 이미 알고있는 프로그래밍 언어와 배우고있는 프로그래밍 언어 간의 유사점과 차이점을 이해하는 좋은 방법입니다.

파일에서 줄 읽기 : One-Liner

Bash에서는 while 명령 줄에서 루프를 실행하여 파일에서 각 텍스트 줄을 읽고 작업을 수행합니다. 텍스트 파일은 “data.txt”입니다. 그것은 한 해의 달 목록을 보유하고 있습니다.

January
February
March
.
.
October
November
December

우리의 간단한 한 줄은 다음과 같습니다.

while read line; do echo $line; done < data.txt

광고

그만큼 while 루프는 파일에서 한 줄을 읽고 작은 프로그램의 실행 흐름이 루프의 본문으로 전달됩니다. 그만큼 echo 명령은 터미널 창에 텍스트 줄을 씁니다. 더 이상 읽을 줄이없고 루프가 완료되면 읽기 시도가 실패합니다.

한 가지 멋진 트릭은 파일을 루프로 리디렉션하는 기능입니다. 다른 프로그래밍 언어에서는 파일을 열고 읽은 다음 완료되면 다시 닫아야합니다. Bash를 사용하면 파일 리디렉션을 사용하고 셸이 모든 저수준 항목을 처리하도록 할 수 있습니다.

물론,이 한 줄짜리는 그다지 유용하지 않습니다. Linux는 이미 cat 명령은 우리를 위해 정확히 수행합니다. 세 글자로 된 명령을 대체 할 수있는 긴 방법을 만들었습니다. 그러나 파일에서 읽는 원리를 눈에 띄게 보여줍니다.

어느 정도까지는 충분히 잘 작동합니다. 월의 이름이 포함 된 다른 텍스트 파일이 있다고 가정합니다. 이 파일에서 개행 문자에 대한 이스케이프 시퀀스가 ​​각 행에 추가되었습니다. ‘data2.txt’라고합니다.

Januaryn
Februaryn
Marchn
.
.
Octobern
Novembern
Decembern

새 파일에서 한 줄짜리를 사용합시다.

while read line; do echo $line; done < data2.txt

백 슬래시 이스케이프 문자 ” ”이 (가) 삭제되었습니다. 그 결과 각 줄에 “n”이 추가되었습니다. Bash는 백 슬래시를 이스케이프 시퀀스의 시작으로 해석합니다. 종종 우리는 Bash가 읽고있는 것을 해석하는 것을 원하지 않습니다. 백 슬래시 이스케이프 시퀀스 및 모든 행 전체를 읽고 자신의 코드 내에서 구문 분석하거나 대체 할 항목을 선택하는 것이 더 편리 할 수 ​​있습니다.

텍스트 줄에서 의미있는 처리 또는 구문 분석을 수행하려면 스크립트를 사용해야합니다.

스크립트를 사용하여 파일에서 행 읽기

여기에 스크립트가 있습니다. “script1.sh”라고합니다.

#!/bin/bash

Counter=0

while IFS='' read -r LinefromFile || [[ -n "${LinefromFile}" ]]; do

    ((Counter++))
    echo "Accessing line $Counter: ${LinefromFile}"

done < "$1"

우리는 Counter 0으로 설정하면 while 고리.

광고

while 줄의 첫 번째 문장은 IFS='' . IFS 내부 필드 구분 기호를 나타냅니다. Bash가 단어 경계를 식별하는 데 사용하는 값을 보유합니다. 기본적으로 read 명령은 선행 및 후행 공백을 제거합니다. 파일에서 줄을 그대로 읽으려면 다음을 설정해야합니다. IFS 빈 문자열이됩니다.

값을 설정하는 것처럼 루프 외부에서 한 번 설정할 수 있습니다. Counter . 그러나 더 복잡한 스크립트, 특히 사용자 정의 함수가 많은 스크립트를 사용하면 IFS 스크립트의 다른 곳에서 다른 값으로 설정할 수 있습니다. 보장 IFS 매번 빈 문자열로 설정됩니다. while loop iterates는 그 동작이 무엇인지 알 수 있도록 보장합니다.

한 줄의 텍스트를 다음과 같은 변수로 읽어 들일 것입니다. LinefromFile . 우리는 -r (백 슬래시를 일반 문자로 읽음) 옵션은 백 슬래시를 무시합니다. 그들은 다른 캐릭터처럼 취급되며 특별한 대우를받지 않습니다.

두 가지 조건이 while 루프를 사용하고 루프 본문에서 텍스트를 처리 할 수 ​​있습니다.

  • read -r LinefromFile : 파일에서 텍스트 행을 성공적으로 읽은 경우 read 명령은 성공 신호를 while , 그리고 while 루프는 실행 흐름을 루프 본문으로 전달합니다. 참고 read 명령을 성공적으로 읽은 것으로 간주하려면 텍스트 줄 끝에 개행 문자가 표시되어야합니다. 파일이 POSIX 호환 텍스트 파일이 아닌 경우 마지막 줄에 개행 문자가 포함될 수 없습니다. 만약 read 명령은 줄이 줄 바꿈으로 끝나기 전에 EOF (파일 끝 마커)를 확인합니다. 아니 성공적인 읽기로 취급하십시오. 이 경우 텍스트의 마지막 줄이 루프 본문으로 전달되지 않고 처리되지 않습니다.
  • [ -n "${LinefromFile}" ] : POSIX와 호환되지 않는 파일을 처리하려면 몇 가지 추가 작업이 필요합니다. 이 비교는 파일에서 읽은 텍스트를 확인합니다. 개행 문자로 끝나지 않으면이 비교는 여전히 성공을 반환합니다. while 고리. 이렇게하면 후행 줄 조각이 루프 본문에 의해 처리됩니다.

이 두 절은 OR 논리 연산자로 구분됩니다.” || ”그래서 어느 한 쪽 절은 성공을 반환하고 검색된 텍스트는 개행 문자가 있는지 여부에 관계없이 루프 본문에 의해 처리됩니다.

광고

루프 본문에서 Counter 하나에 의해 변수 및 사용 echo 일부 출력을 터미널 창으로 보냅니다. 줄 번호와 각 줄의 텍스트가 표시됩니다.

리디렉션 트릭을 사용하여 파일을 루프로 리디렉션 할 수 있습니다. 이 경우 스크립트에 전달 된 첫 번째 명령 줄 매개 변수의 이름을 보유하는 변수 인 $ 1을 리디렉션합니다. 이 트릭을 사용하면 스크립트가 작업 할 데이터 파일의 이름을 쉽게 전달할 수 있습니다.

스크립트를 복사하여 편집기에 붙여넣고 “script1.sh”라는 파일 이름으로 저장합니다. 사용 chmod 실행 가능하게 만드는 명령.

chmod +x script1.sh

스크립트가 data2.txt 텍스트 파일과 그 안에 포함 된 백 슬래시를 어떻게 만드는지 살펴 보겠습니다.

./script1.sh data2.txt

줄의 모든 문자는 그대로 표시됩니다. 백 슬래시는 이스케이프 문자로 해석되지 않습니다. 일반 문자로 인쇄됩니다.

함수에 라인 전달

우리는 여전히 텍스트를 화면에 에코하고 있습니다. 실제 프로그래밍 시나리오에서 우리는 텍스트 줄로 더 흥미로운 일을 할 것입니다. 대부분의 경우 다른 함수에서 행의 추가 처리를 처리하는 것이 좋은 프로그래밍 관행입니다.

여기에 우리가 할 수있는 방법이 있습니다. 이것은“script2.sh”입니다.

#!/bin/bash

Counter=0

function process_line() {

    echo "Processing line $Counter: $1"

}

while IFS='' read -r LinefromFile || [[ -n "${LinefromFile}" ]]; do

    ((Counter++))
    process_line "$LinefromFile"

done < "$1"
광고

우리는 우리를 정의합니다 Counter 이전과 같이 변수를 정의한 다음 process_line() . 함수의 정의가 나타나야합니다. 전에 함수는 스크립트에서 먼저 호출됩니다.

우리의 함수는 각 반복에서 새로 읽은 텍스트 줄에 전달됩니다. while 고리. 함수 내에서 해당 값에 액세스하려면 $1 변하기 쉬운. 함수에 두 개의 변수가 전달 된 경우 다음을 사용하여 해당 값에 액세스 할 수 있습니다. $1$2 , 더 많은 변수를 위해 등등.

While 루프는 주로 동일합니다. 루프 본문에는 하나의 변경 사항 만 있습니다. 그만큼 echo 전화로 대체되었습니다. process_line() 함수. 함수를 호출 할 때 함수 이름에 “()”대괄호를 사용할 필요가 없습니다.

텍스트 줄을 포함하는 변수의 이름, LinefromFile 는 함수에 전달 될 때 따옴표로 묶여 있습니다. 이것은 그 안에 공백이있는 라인을 충족시킵니다. 따옴표가 없으면 첫 번째 단어는 다음과 같이 처리됩니다. $1 함수에 의해 두 번째 단어는 $2 , 등등. 인용 부호를 사용하면 전체 텍스트 줄이 다음과 같이 처리됩니다. $1. 이것은 아니 똑같다 $1 스크립트에 전달 된 동일한 데이터 파일을 보유합니다.

때문에 Counter 함수 내부가 아니라 스크립트의 본문에서 선언되었으므로 내부에서 참조 할 수 있습니다. process_line() 함수.

위의 스크립트를 편집기에 복사하거나 입력하고 “script2.sh”라는 파일 이름으로 저장합니다. 다음으로 실행 가능하게 만드십시오. chmod :

chmod +x script2.sh

광고

이제이를 실행하고 새 데이터 파일 인“data3.txt”를 전달할 수 있습니다. 여기에는 달의 목록과 많은 단어가있는 한 줄이 있습니다.

January
February
March
.
.
October
November nMore text "at the end of the line"
December

우리의 명령은 다음과 같습니다.

./script2.sh data3.txt

줄은 파일에서 읽고 하나씩 전달됩니다. process_line() 함수. 백 스페이스, 따옴표 및 여러 단어가 포함 된 홀수 줄을 포함하여 모든 줄이 올바르게 표시됩니다.

빌딩 블록은 유용합니다

관용구는 그 언어에 고유 한 무언가를 포함해야한다고 말하는 일련의 생각이 있습니다. 그것은 내가 구독하는 믿음이 아닙니다. 중요한 것은 언어를 잘 사용하고 기억하기 쉬우 며 코드에서 일부 기능을 구현하는 안정적이고 강력한 방법을 제공한다는 것입니다.