"읽는 동안 -r"에서 "\r"을 내용 없음으로 처리

"읽는 동안 -r"에서 "\r"을 내용 없음으로 처리

텍스트 파일을 한 줄씩 읽는 코드 줄이 있습니다.

텍스트 파일은 Windows 사용자가 생성하는 경우도 있고 Unix 사용자가 생성하는 경우도 있습니다. 그래서 때로는 줄의 끝이 보이기도 \r\n하고 때로는 그냥 보이기도 합니다 \n.

내 스크립트가 두 경우를 모두 처리하고 개행 문자가 \r, 또는 \n, \r\n또는 인지 여부에 관계없이 각 줄에 개별적으로 도달하기를 원합니다 \n\r.

while read -r textFileLines; do ... something ...; done < text_file.txt

이 코드일하다\n\r각 줄 끝에 (LF CR)이 있지만아니요내가 \r\n줄 끝에 있을 때!

시험

  • 다음을 사용하여 새 텍스트 파일을 만듭니다.Notepad++ v7.5.4

    여기에 이미지 설명을 입력하세요.

  • while read -r LINE; do echo "$LINE"; done < /cygdrive/d/test_text.txt

  • 터미널 출력:

    first_line
    second_line
    third_string
    

fourth_output이 행이 표시 되지 않는 이유는 무엇인가요 ?

답변1

일부 파일은 DOS 텍스트 파일이고 다른 파일은 Unix 텍스트 파일인 경우 스크립트는 다음과 같은 방법으로 모든 데이터를 전달할 수 있습니다 dos2unix.

dos2unix <filename |
while IFS= read stuff; do
   # do things with "$stuff"
done 

결과적으로 Unix 텍스트 파일은 수정되지 않습니다.

Mac 줄 바꿈 문제를 추가로 처리하기 위해 저는믿다당신은 할 수 있어야합니다

dos2unix <filename | mac2unix |
while IFS= read stuff; do
   # do things with "$stuff"
done 

마지막 줄은 read종료되지 않아 전혀 줄이 아니기 때문에 루프에 의해 출력되지 않습니다.

파일의 마지막 줄에 종료 개행 문자가 없는지 감지하고 그렇지 않은 경우 다음 위치에 추가하십시오 bash.

if [ "$( tail -c 1 filename )" != $'\n' ]; then
    printf '\n' >>filename
fi

관련된:

답변2

fourth_output이 행이 표시 되지 않는 이유는 무엇인가요 ?

이미지에서 파일의 마지막 줄 끝에 개행 문자가 누락되었습니다. read구분 기호(새 줄)를 읽는 경우에만 true를 반환하고, 마지막 줄의 끝에 해당 구분 기호가 존재하지 않기 때문에 readfalse를 반환하고 마지막 불완전한 줄을 인쇄하지 않고 루프가 종료됩니다.

이는 캐리지 리턴과 관련이 없으며 마지막 줄에 NL이 없으면 NL만 있어도 동작은 동일합니다.

file1CRLF 줄로 끝나는 두 줄은 다음과 같습니다 .

$ cat -A file1
foo^M$
bar^M$
$ while read x ; do echo "<$x>"; done < file1
>foo
>bar

file2두 번째 줄 끝에 있는 줄이 누락되었습니다.

$ cat -A file2 ; echo
foo^M$
bar
$ while read x ; do echo "<$x>"; done < file2
>foo

루프가 마지막 줄 조각도 처리하도록 하려면 반환에 실패할 read때 변수에 데이터가 포함되어 있는지 확인 해야 합니다.read

$ while read -r x || [ "$x" ] ; do echo "<$x>"; done < file2
>foo
<bar>

CR을 제거하려면 루프(예: Bash/ksh/zsh)에서 제거하거나 x=${x%$'\r'};or와 같은 전처리기 파일을 사용할 수 있습니다.tr -d '\r'dos2unix

답변3

구현하다:

$ [ -n "$(tail -c1 infile)" ] && echo >> infile
$ sed 's/\r$\|^\r//g;s/\r/\n/g' infile | while IFS= read -r line
> do echo "$line" ; done
DOS       line
second     DOS
old  mac   line
new  mac   line
end\n\rreverse
linux      line
new linux  line

모든 문제가 해결되었습니다.


설명하다:

누락된 마지막 개행 문자를 수정하려면 다음을 사용하십시오.

[ -n "$(tail -c1 infile)" ] && echo >> infile

후행 줄 바꿈은 필요한 경우에만 추가됩니다(올바른 파일은 변경되지 않음).

그러면 변환할 수 있습니다

  • \r\n(DOS 스타일) ~ \n(줄 끝의 \r만 제거)
  • \n\r(잘못된 DOS 스타일?)을 1로 \n(줄 시작 부분에서 \r 제거)
  • 그런 다음 (수정된 MAC의 경우) \r(이전 MAC)을 다음으로 변환합니다.\n

(GNU) sed를 한 번만 호출하세요.

sed 's/\r$\|^\r//g;s/\r/\n/g' infile

텍스트 파일이 다음 테스트 파일과 같은 경우:

$ cat infile
DOS       line
second     DOS
new  mac   line
end\n\rreverse
linux      line
new linux  line
no  end   line

$ cat -A infile
DOS       line^M$
second     DOS^M$
old  mac   line^Mnew  mac   line$
end\n\rreverse$
^Mlinux      line$
new linux  line$
no  end   line

$  od -An -tc infile
   D   O   S                               l   i   n   e  \r  \n
   s   e   c   o   n   d                       D   O   S  \r  \n
   o   l   d           m   a   c               l   i   n   e  \r
   n   e   w           m   a   c               l   i   n   e  \n
   e   n   d   \   n   \   r   r   e   v   e   r   s   e  \n  \r
   l   i   n   u   x                           l   i   n   e  \n
   n   e   w       l   i   n   u   x           l   i   n   e  \n
   n   o           e   n   d               l   i   n   e

답변4

이를 수행하기 위한 명확한 도구가 있습니다. 파일에서 제거 하는 데 사용할 수 있는 보다 일반적인 것은 \r\n입니다 dos2unix.

시스템에서 이 기능을 사용할 수 없는 경우 다음 명령 중 하나를 사용하여 textFileLines변수에 대해 유사한 작업을 수행할 수 있습니다.

$ echo "$textFileLines" | awk 1 RS='\r\n' ORS=
sed 1
$ echo "$textFileLines" | sed -e 's/\r//g'
sed 2
$ echo $textFileLines | sed $'s/\r//'
$ echo "$textFileLines" | tr -d '\r'

물론 이를 수행하는 다른 방법도 많이 있습니다. 이는 가장 일반적인 방법 중 일부일 뿐입니다.

인용하다

관련 정보