줄 바꿈으로 끝나지 않을 줄 지향 파일을 읽습니다.


11

/tmp/urlFile각 줄이 URL을 나타내는 위치에 파일이 있습니다 . 다음과 같이 파일에서 읽으려고합니다.

cat "/tmp/urlFile" | while read url
do
    echo $url
done

마지막 줄이 줄 바꿈 문자로 끝나지 않으면 해당 줄을 읽을 수 없습니다. 왜 궁금해?

새 줄로 끝나는 지 여부에 관계없이 모든 줄을 읽을 수 있습니까?



2
Hah @ Stéphane 나는 거기 TBD를 좋아한다 ;-).
Stephen Kitt

2
후행 줄 바꿈이 없으면 추가하는 또 다른 방법입니다. awk 1 /tmp/urlFile.. soawk 1 /tmp/urlFile | while ...
muru

@muru, 그것은 다른 어떤 것보다 더 나은 대답입니다.
와일드 카드

1
읽지 못 했는지 묻기 때문에 : stackoverflow.com/a/729795/1968
Konrad Rudolph

답변:


13

당신은 할 것입니다 :

while IFS= read -r url || [ -n "$url" ]; do
  printf '%s\n' "$url"
done < url.list

(효과적으로,이 루프는 마지막 (비) 라인에서 누락 된 줄 바꿈을 다시 추가합니다).

또한보십시오:


감사. 링크 된 기사를 읽었을 때 "루프가 마지막 (비) 줄에서 누락 된 줄 바꿈을 다시 추가하는"이유가 무엇입니까?
Tim

1
@Tim Stephane이 의미하는 것은 printf여기에있는 모든 호출이 있기 때문에 출력에서 ​​누락 된 줄 바꿈을 다시 추가한다는 것 \n입니다.
Sergiy Kolodyazhnyy

6

이것은 부분적으로 해결 된 것으로 보입니다 readarray -t.

readarray -t urls "/tmp/urlFile"
for url in "${urls[@]}"; do
    printf '%s\n' "$url"
done

그러나 이것이 합리적 크기의 파일에 대해서는 작동하지만이 솔루션은 매우 큰 파일에 잠재적 인 새로운 문제를 유발합니다. 먼저 파일을 배열로 읽은 다음 반복해야합니다. 매우 큰 파일의 경우 시간이 많이 걸리고 메모리를 많이 소비 할 수 있으며 잠재적으로 오류가 발생할 수 있습니다.


감사. 어느 부분이 해결되고 어떤 부분이 해결되지 않습니까?
Tim

후행 줄 바꿈이없는 문제를 해결하지만 파일을 먼저 배열로 읽은 다음 반복해야하기 때문에 매우 큰 파일의 잠재적 인 새로운 문제가 발생합니다.
DopeGhoti

1
@DopeGhoti 좋은 정보입니다-답변에 직접 추가해 주시겠습니까?
RJ 헌터

그 대답이 너무 수정되었습니다.
DopeGhoti

5

에 의해 정의 , 텍스트 파일은 라인의 순서로 구성되어 있습니다. 라인은 개행 문자로 끝납니다. 따라서 텍스트 파일은 비어 있지 않으면 개행 문자로 끝납니다.

read내장은 텍스트 파일을 읽을 수하기위한 것입니다. 텍스트 파일을 전달하지 않으므로 원활하게 작동하기를 기대할 수 없습니다. 쉘은 모든 행을 읽습니다. 건너 뛰는 것은 마지막 행 다음에 나오는 추가 문자입니다.

마지막 행이 누락되었을 수있는 형식이 잘못된 입력 파일이 있으면 개행을 추가 할 수 있습니다.

{ cat "/tmp/urlFile"; echo; } | 

텍스트 파일이어야하지만 마지막 줄 바꿈이없는 파일은 종종 Windows 편집기에서 생성됩니다. 이것은 일반적으로 Unix의 LF가 아닌 CR LF 인 Windows 줄 끝과 함께 사용됩니다. CR 문자는 어디에서나 거의 유용하지 않으며 어떤 경우에도 URL에 표시 될 수 없으므로 제거해야합니다.

{ <"/tmp/urlFile" tr -d '\r'; echo; } | 

입력 파일의 형식이 양호하고 개행으로 끝나는 echo경우 빈 줄이 추가됩니다. URL은 비워 둘 수 없으므로 빈 줄은 무시하십시오.

또한 read직선으로 행을 읽지 않습니다. URL의 경우 앞뒤 공백을 무시합니다. 행 끝의 백 슬래시를 이스케이프 문자로 취급하여 다음 행을 첫 번째 빼기 백 슬래시-줄 바꾸기 시퀀스와 결합시킵니다. 이는 바람직하지 않습니다. 따라서 -r옵션을에 전달해야 합니다 read. read오히려 옳은 것이 되기는 매우 드 rare니다 read -r.

{ <"/tmp/urlFile" tr -d '\r'; echo; } | while read -r url
do
  if [ -z "$url" ]; then continue; fi
  
done

3

글쎄, read그것은 줄 바꿈하기 전에 파일의 마지막을 충족하는 경우 falsy 값을 반환하지만,이 경우에도, 그것은 여전히 읽은 값을 할당합니다. 따라서 최종 호출이 read빈 줄 이외의 것을 반환 하는지 확인 하고 정상적으로 처리합니다. 그래서 후에 만 루프 종료 read반환 거짓을 하고 라인이 비어 있습니다 :

#!/bin/sh
while IFS= read -r line || [ "$line" ]; do 
    echo "line: $line"
done

$ printf 'foo\nbar' | sh ./read.sh 
line: foo
line: bar
$ printf 'foo\nbar\n' | sh ./read.sh 
line: foo
line: bar

1

다른 방법은 다음과 같습니다.

읽기가 행 끝이 아닌 파일 끝에 도달하면 데이터를 읽고 변수에 지정하지만 0이 아닌 상태로 종료됩니다. 루프가 "읽는 동안; 물건을;

따라서 읽기 종료 상태를 직접 테스트하는 대신 플래그를 테스트하고 읽기 명령을 루프 본문 내에서 해당 플래그로 설정하십시오. 이런 식으로 읽기 종료 상태에 관계없이 전체 루프 본문이 실행됩니다. 읽기는 루프가 실행 될지 여부를 결정하는 요소가 아니라 다른 루프의 명령 목록 중 하나 일뿐입니다.

DONE=false
until $DONE ;do
read || DONE=true
echo $REPLY 
done < /tmp/urlFile

여기 에서 참조 하십시오 .


1
고양이 "/ tmp / urlFile"| URL을 읽는 동안
하다
    에코 $ url
끝난

쓸모없는 사용입니다cat .

아이러니하게도 cat여기서 프로세스를 실제로 유용한 것으로 대체 할 수 있습니다 . POSIX 시스템이 누락 된 줄 바꿈을 추가하고 파일을 적절한 POSIX 텍스트 파일로 만드는 도구입니다.

sed -e '$ a \' "/ tmp / urlFile"| -r url을 읽는 동안
하다
    printf "% s \ n" "$ {url}"
끝난

추가 자료


1
입력이 개행 문자로 끝나지 않을 때 POSIX는 sed의 동작을 지정하지 않습니다. 또한 LINE_MAX보다 큰 행 read이있는 경우 동작은 이러한 경우에 지정됩니다.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.