对 awk 中的每一行重复外部命令

对 awk 中的每一行重复外部命令

剪贴板中包含以下内容:

curl "foo" --compressed ;
curl "bar" --compressed ;
curl "baz" --compressed ;

以下命令为每个剪贴板行创建一行:

pbpaste | awk '{"pwgen 10 1" | getline pass; print substr($0, 1, length($0) -1) ">>myfile-" pass ".jpg"}'

生成以下输出:

curl "foo" --compressed >>myfile-du7EeHegh7.jpg
curl "bar" --compressed >>myfile-du7EeHegh7.jpg
curl "baz" --compressed >>myfile-du7EeHegh7.jpg

问题:

这里的问题是,pwgen 10 1似乎在开始时只执行一次,而我希望它为每个新的剪贴板行执行,因此为每行生成一个新的唯一文件名。如何确保pwgen重复调用而不是在开始时只执行一次?

期望的输出:

# each filename is unique
curl "foo" --compressed >>myfile-zus83j10ai.jpg
curl "bar" --compressed >>myfile-nbjfo2pa9d.jpg
curl "baz" --compressed >>myfile-ahqdugpo90.jpg

答案1

在 awk 中使用外部命令并使用getline from a Pipe,最好将命令分配给一个变量my_command="my external command here",然后用它调用my_command |getline to_save它,你应该close(my_command)它是为了使每次运行的输出都不同;还建议执行close(my_command)inBEGIN{...}块以确保没有命令为my_command.

另外对 getline 返回代码进行测试,如果成功则继续;所以你必须这样做:

pbpaste |awk 'BEGIN{ close(cmd); }
{ cmd="pwgen 10 1";
  if (cmd | getline pass) {
      print substr($0, 1, length($0) -1) ">>myfile-" pass ".jpg";
      close(cmd);
  } else { print "running command failed!"; exit 1; }
}'

然而,如果命令本身失败, getline 仍然会返回成功返回代码,因为我们不检查命令成功/失败,为了对命令状态进行测试,我们可以这样做:

pbpaste |awk 'BEGIN{ close(cmd); }
{ cmd="pwgen 10 1 || echo failed";
  if ((cmd | getline pass)>0 && pass!="failed") {
      print substr($0, 1, length($0) -1) ">>myfile-" pass ".jpg";
      close(cmd);
  } else { print "running command failed!"; exit 1; }
}'

引用手册:

如果文件名相同或相同的 shell 命令getline 在 awk 程序执行期间多次使用(请参阅使用 getline 显式输入部分),文件被打开(或命令被执行)仅限第一次。此时,将从该文件或命令中读取第一条输入记录。下次将同一个文件或命令与 getline 一起使用时,将从中读取另一条记录,依此类推。

从上面的链接使用 getline 显式输入提及:

getline 命令如果找到记录则返回 1,如果遇到文件末尾则返回 0。如果获取记录时出现错误,例如无法打开文件,则 getline 返回 -1。在这种情况下,gawk 将变量 ERRNO 设置为描述发生的错误的字符串。

也可以看看:

相关内容