为给定文件 F 的每一行 L 运行特定命令 C ,然后移动 C(L) 运行失败的每个 L 的干净方法是什么?

为给定文件 F 的每一行 L 运行特定命令 C ,然后移动 C(L) 运行失败的每个 L 的干净方法是什么?

比如说

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

是 的内容urls.txt。我想运行-where<command> <url>的每个 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

我知道 shell 运行的每个命令的退出状态都可以通过变量 获得$?,该0变量表示命令的成功执行,而所有其他整数表示失败。不过,我不确定如何构建一个包含此命令的复合命令,从正在读取的文件中删除行,并将它们附加到另一个文件中。

答案1

使用bash,您可以循环获取 url 并测试命令curl--fail选项curl似乎很适合在脚本内使用,请参阅: 如何检查诸如curl之类的命令是否完成而没有错误

所以它可能是这样的:

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

并用成功的网址覆盖您的文件。

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=读取-r行”

答案2

使用 zsh,你可以这样做:

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

这样,badgood文件仅被打开一次,并且仅当urls其本身可以打开以供读取时。

相关内容