テキストファイルを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
を使用して新しいテキストファイルを作成します
while read -r LINE; do echo "$LINE"; done < /cygdrive/d/test_text.txt
ターミナルでの出力:
first_line
second_line
third_string
fourth_output
行が表示されないのはなぜですか?
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
関連:
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
などでファイルを前処理します。
実行:
$ [ -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を削除)\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