web-dev-qa-db-ja.com

「whileread-r」では「\ r」を何も扱わない

テキストファイルを1行ずつ読み取るこのコード行があります。

テキストファイルは、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)で機能しますが、NOT行末に\r\nがある場合はwork

[〜#〜]テスト[〜#〜]

  • Notepad++ v7.5.4を使用して新しいテキストファイルを作成します

    enter image description here

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

  • ターミナルでの出力:

    first_line
    second_line
    third_string
    

fourth_output行が表示されないのはなぜですか?

1
vivoru

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

関連:

0
Kusalananda

fourth_output行が表示されないのはなぜですか?

画像では、ファイルの最後の行の終わりに改行がありません。 readは、区切り文字(改行)を読み取る場合にのみtrueを返します。これは最後の行の終わりにないため、readはfalseを返し、ループは終了し、最後の不完全な行は印刷されません。

これはキャリッジリターンとは関係ありません。最後の行にNLがない場合、NLだけでも動作は同じです。

ここで、file1にはCRLF行末の2行があります。

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

file2には、2行目で終わる行がありません。

$ 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を削除したい場合は、ループ内でCRを削除できます。 x=${x%$'\r'};(Bash/ksh/zsh内)、またはtr -d '\r'またはdos2unixなどでファイルを前処理します。

1
ilkkachu

実行:

$ [ -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を削除)
  • 次に(ペアを修正して)convert \r(古いMAC)から\n

(GNU)sedのたった1回の呼び出しで:

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
0
Isaac