使用find -exec重定向stdout并且不创建新shell

jse*_*ras 18 unix linux

我有一个只写数据的脚本stdout.我需要为多个文件运行它并为每个输入文件生成不同的输出文件,我想知道如何使用find -exec它.所以我基本上尝试了几种变体(我cat为了可测试性而替换了脚本):

find * -type f -exec cat "{}" > "{}.stdout" \;
Run Code Online (Sandbox Code Playgroud)

但由于所有数据都被写入一个字面命名的文件,因此无法使其正常工作{}.stdout.

最终,我可以使用它:

find * -type f -exec sh -c "cat {} > {}.stdout" \;
Run Code Online (Sandbox Code Playgroud)

但是,虽然这个最新的形式适用cat,我的脚本需要通过几个初始化脚本加载环境变量,因此我最终得到:

find * -type f -exec sh -c "initscript1; initscript2; ...;  myscript {} > {}.stdout" \;
Run Code Online (Sandbox Code Playgroud)

这似乎是浪费,因为我已经在我当前的shell中初始化了所有内容.

有没有更好的方法来做到这一点find?欢迎其他单行.

小智 13

你可以用eval做到这一点.它可能很难看,但是必须为此制作一个shell脚本.此外,这一切都在一条线上.例如

find -type f -exec bash -c "eval md5sum {}  > {}.sum " \;
Run Code Online (Sandbox Code Playgroud)

  • `bash -c` 是这里的重点,`eval` 实际上并没有做任何有用的事情。但是您并没有避开外壳。 (3认同)
  • 因此,安全的改写是为f找到-type f -exec bash -c';做md5sum“ $ f”>“ $ f.sum”; 完成了_ +`,但当然也不会避免使用shell(并且基本上复制了@CharlesDuffy的现有答案)。 (2认同)

Wil*_*ell 9

一个简单的解决方案是在脚本周围放置一个包装器:

#!/bin/sh

myscript "$1" > "$1.stdout"
Run Code Online (Sandbox Code Playgroud)

调用它myscript2并使用find调用它:

find . -type f -exec myscript2 {} \;
Run Code Online (Sandbox Code Playgroud)

请注意,虽然find的大多数实现允许您执行您已完成的操作,但从技术上讲,如果您{}在参数列表中使用多次,则未指定查找的行为-exec.

  • 你的`find`特定实现的手册说明它有效,但标准上写着:`如果存在多个只包含两个字符"{}"的参数,则行为未指定.这不是什么大不了的事,但是它可以燃烧你(在这一点上它突然变得很重要!) (3认同)
  • 更重要的缺点是像`-exec sh -c"myscript {}> {} .stdout"\;`之类的东西会导致恶意文件名面对任意代码执行.`-exec sh -c'myscript"$ 1">"$ 1.stdout"'sh {} \;`更安全. (3认同)
  • 但是在`find`手册中,`-exec`中的某个地方可以说:_字符串'{}'被当前正在处理命令的参数中处理的文件名所取代,而不仅仅是在它所在的参数中单独,如在某些版本的find._ [link](http://unixhelp.ed.ac.uk/CGI/man-cgi?find).不过,谢谢你的解决方法. (2认同)