Bash: 명령의 출력을 한 번에 한 줄씩 읽는 방법은 무엇입니까?

Bash: 명령의 출력을 한 번에 한 줄씩 읽는 방법은 무엇입니까?

.bashrc 파일을 사용하여 bash에서 명령 출력을 읽으려고 합니다 while loop.

while read -r line
do
    echo "$line"
done <<< $(find . -type f)

내가 얻는 결과

ranveer@ranveer:~/tmp$ bash test.sh
./test.py ./test1.py ./out1 ./test.sh ./out ./out2 ./hello
ranveer@ranveer:~/tmp$ 

그 후 나는 시도했다

$(find . -type f) | 
while read -r line
do
    echo "$line"
done 

하지만 오류가 발생했습니다 test.sh: line 5: ./test.py: Permission denied.

그러면 현재 전체 줄을 한 번에 읽는다고 생각하기 때문에 한 줄씩 어떻게 읽습니까?

원하는 출력:

./test.py
./test1.py
./out1
./test.sh
./out
./out2
./hello

답변1

버그가 있습니다. < <(command)필요하지 않습니다.<<<$(command)

< <( )프로세스 교체, $()명령 대체그리고 <<<여기에 있는 문자열.

답변2

파이프를 사용하려는 경우 명령 대체가 필요하지 않습니다. 기본적 read으로 읽기 stdin이므로 입력을 파이프할 수 있습니다.

find . -type f -print0 |
while read -r -d '' line
do
    echo "$line"
done

아니면 한 줄로

find . -type f -print0 | while read -r -d '' line; do echo "$line"; done

-print0및 를 사용하면 -d ''파일 이름에 새 줄이 생길 수 있으므로 기본적으로 줄 끝이 다음임을 의미합니다 read( 및 를 사용하여 변경할 수 있음 -d). ''위에서 사용된 것은 실제로 널 바이트 bash(와 동일 $'\0')입니다.

find이미 언급한 또 다른 방법은 's 옵션을 사용하는 것입니다 -exec. 이는 성능 측면에서 가장 좋은 옵션일 가능성이 높습니다( -exec cmd {} +처리되는 모든 행에 대해 프로세스를 분기하지 않도록 변형을 사용하는 것을 기억하세요). 그러나 실제로는 while루프 내에서 수행하는 작업과 처리 중인 데이터의 양 에 따라 달라집니다 . 귀하의 경우에는 그 차이가 무시할 수 있거나 허용될 수 있습니다.

답변3

파일 이름에 개행 문자가 포함되는 것을 방지할 수 있는 것은 없습니다. 각 파일에 대해 명령을 실행하는 정식 방법확립된예를 검색하여

find . -type f -exec cmd {} \;

Bash에서 작업을 수행하려면 다음을 수행하십시오.

find . -type f -exec bash -c '
  for file do
    something with "$file"
  done' bash {} +

또한 스크립트에서 "읽기" 명령을 호출하는 정식 방법은 다음과 같습니다(입력에 대한 추가 처리를 원하지 않는 경우).

IFS= read -r var

-r백슬래시 문자(구분 기호 및 줄 바꿈에 대한 이스케이프 문자)의 특수 처리를 중지하고 readIFS=는 구분 기호 목록을 빈 문자열로 설정합니다 read(그렇지 않으면 공백 문자가 목록에 있으면 입력 시작에서 제거됩니다). 그리고 끝).

셸에서 루프를 사용하는 것은 일반적으로 나쁜 생각입니다(수백 개의 2급 도구에 대해 하나 이상의 도구를 순차적으로 실행하는 대신 여러 도구를 사용하여 동시에 작업을 수행할 수 있는 셸에서 작업을 수행하는 방식이 아닙니다).

답변4

작은 수정Stefan Chazeras의 답변.

find . -type f -exec bash -c 'echo $0; head $0;' {} \;

이는 제공한 스크립트가 bash -c첫 번째 매개변수를 사용하는 방법을 보여줍니다.

관련 정보