与えられたファイルFの各行Lに対して特定のコマンドCを実行し、失敗した各Lに対してC(L)を移動するきちんとした方法は何ですか?

与えられたファイルFの各行Lに対して特定のコマンドCを実行し、失敗した各Lに対してC(L)を移動するきちんとした方法は何ですか?

例えば

https://example.nosuchtld
https://example.net
https://example.org
https://example.willfail

うん内容urls.txt。すべてのURL /行に対して-whereを実行したいと思います<command> <url>urls.txt<command>curl

cat urls.txt | xargs -n1 curl

または

<urls.txt xargs -n1 curl

例えば。curl正常に編集されなかったすべてのURL /行が必要です(最初と最後)。

  1. 削除されましたurls.txt
  2. 別のファイルに追加 -nope.txtすでに存在しない場合は作成

urls.txt次のように去る

https://example.net
https://example.org

nope.txtそして

https://example.nosuchtld
https://example.willfail

シェルで実行される各コマンドの終了ステータスは、コマンドの正常な実行を示す変数を介して使用できますが、他のすべての整数は失敗を示します$?0しかし、それを含み、読み込んでいるファイルから行を削除し、他のファイルに追加する複合コマンドを作成する方法がわかりません。

答え1

を使用すると、bash繰り返しURLを取得してコマンドをテストできますcurl--failこのオプションはcurlスクリプト内で使用することをお勧めします。以下を参照してください。 カールなどのコマンドがエラーなしで完了したことを確認する方法

したがって、次のように見えます。

while read -r url; do
    curl -f "$url" && outputfile='success.txt' || outputfile='nope.txt'
    printf "%s\n" "$url" >> "$outputfile"
done < urls.txt

成功したURLでファイルを上書きします。

mv success.txt urls.txt

または、mapfile次を使用して行を配列に配置します。

mapfile -t urls < urls.txt

for url in "${urls[@]}"; do
    curl -f "$url" && outputfile='success.txt' || outputfile='nope.txt'
    printf "%s\n" "$url" >> "$outputfile"
done

URLにスペースはありません。引数が文字を含む完全な行であるコマンドを実行する必要がある場合、この投稿は各行を読み取るのに役立ちます。「IFS=read-r-line」を理解する

答え2

zshを使用すると、次のことができます。

while IFS= read -ru3 url; do
  curl -- $url
  print -ru $(( $? ? 4 : 5 )) -- $url
done 3< urls 4> bad 5> good

このようにして、badファイルgoodは一度だけ開き、urlsそのファイル自体を読み取るために開くことができる場合にのみ開きます。

関連情報