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

时间:2013-02-22 18:10:54

标签: linux unix

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

find * -type f -exec cat "{}" > "{}.stdout" \;

但由于所有数据都被写入名为{}.stdout的文件,因此无法正常工作。

最终,我可以使用它:

find * -type f -exec sh -c "cat {} > {}.stdout" \;

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

find * -type f -exec sh -c "initscript1; initscript2; ...;  myscript {} > {}.stdout" \;

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

使用find有更好的方法吗?欢迎其他单行。

3 个答案:

答案 0 :(得分:9)

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

find -type f -exec bash -c "eval md5sum {}  > {}.sum " \;

答案 1 :(得分:8)

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

#!/bin/sh

myscript "$1" > "$1.stdout"

将其称为myscript2并使用find:

调用它
find . -type f -exec myscript2 {} \;

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

答案 2 :(得分:3)

如果您导出您的环境变量,它们已经存在于子shell中(如果您使用sh -c而不是export -f,那么您的父shell它本身就是bash,那么你也可以在父shell中导出 functions 并让它们在子节点中使用;参见-exec ... {} +)。

此外,通过使用set -a # turn on automatic export of all variables source initscript1 source initscript2 # pass as many filenames as possible to each sh -c, iterating over them directly find * -name '*.stdout' -prune -o -type f \ -exec sh -c 'for arg; do myscript "$arg" > "${arg}.stdout"' _ {} + ,您可以将shell的数量限制为在命令行上传递所有参数所需的最小可能数量:

while IFS= read -r -d '' filename; do
  myscript "$filename" >"${filename}.out"
done < <(find * -name '*.stdout' -prune -o -type f -print0)

或者,您可以直接在当前shell中执行执行:

find

UsingFind通过<(...)安全正确地讨论批量操作;和BashFAQ #24讨论使用进程替换(Observable.just(s) .flatMap(new Function<String, ObservableSource<String>>() { @Override public ObservableSource<String> apply(final String s) throws Exception { return s.length() < 3 ? Observable.error(new Throwable("len")) : Observable.just(s); } }).flatMap(new Function<String, ObservableSource<String>>() { @Override public ObservableSource<String> apply(final String s) throws Exception { return s.startsWith("a") ? Observable.error(new Throwable("start")) : Observable.just(s); } }) .subscribe(...) 语法)来确保在父shell中执行操作。