我有一个脚本只能将数据写入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
有更好的方法吗?欢迎其他单行。
答案 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中执行操作。