改行で終わらないかもしれない行指向のファイルを読む


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..そうawk 1 /tmp/urlFile | while ...
muru

@muru、それはここの他のどれよりも良い答えです。
ワイルドカード

1
なぜ読まないのと尋ねているので、stackoverflow.com
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それは良い情報です-答えに直接追加することを提案できますか?
RJHunter 2018年

回答が大幅に修正されました。
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オプションをに渡す必要がありますreadreadではなく、正しいことであることが非常にまれですread -r

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

3

まあ、read改行の前にファイルの終わりに到達した場合は偽の値を返しますが、検出した場合でも、読み取った値を割り当てます。したがって、の最後の呼び出しが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

別の方法は次のようになります:

読み取りが行の終わりではなくファイルの終わりに達すると、データを読み取って変数に割り当てますが、ゼロ以外のステータスで終了します。ループが作成されている場合、「読み取り中;何かを実行;完了

そのため、読み取り終了ステータスを直接テストする代わりに、フラグをテストし、ループ本体内から読み取りコマンドにそのフラグを設定させます。この方法では、読み取りの終了ステータスに関係なく、ループ本体全体が実行されます。これは、他のループと同様に、ループ内のコマンドのリストの1つにすぎず、ループが実行されるかどうかの決定要因ではありません。

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
ただし、入力が改行文字で終わっていない場合のsedの動作はPOSIXでは規定されていません。LINE_MAXよりも大きい行がreadある場合も、その場合の動作が指定されます。
ステファンChazelas
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.