假设我有一个文件夹,其中包含名称类似的文件
file1.txt
file2.txt
file2.txt
等等。我想对它们每个人运行一个命令,如下所示:
mycommand file1.txt -o file1-processed.txt
mycommand file2.txt -o file2-processed.txt
mycommand file3.txt -o file3-processed.txt
ETC。
该网站上有几个类似的问题 - 不同之处在于我想将-processed
测试插入到文件名的中间、扩展名之前。
看起来find
应该是完成这项工作的工具。如果没有国旗-o
我也能做到
find *.txt -exec mycommand "{}" ";"
但是,{}
语法给出了整个文件名,例如file1.txt
等,因此我无法-processed
在文件名及其扩展名之间添加“”。使用简单的 bashfor
循环也存在类似的问题。
有没有一种简单的方法来完成这项任务,使用find
或其他方式?
答案1
如果所有要处理的文件都在同一个文件夹中,则不需要使用find
, 并且可以使用本机 shell 通配符。
for foo in *.txt ; do
mycommand "${foo}" -o "${foo%.txt}-processed.txt"
done
shell 习惯用法从 的值中${foo%bar}
删除与模式匹配的最小后缀字符串(在本例中为扩展名),因此我们可以将其替换为您想要的后缀。bar
foo
.txt
答案2
如果您编写要在各种系统上运行的脚本并且考虑可移植性,那么没有什么比for
循环和${var%sfx}
从用户1404316的回答。
但是,如果您正在寻找一种方便的方法在自己的系统上执行类似的操作,那么我衷心推荐GNU 并行,这基本上是xargs
类固醇。这是针对您的特定任务的解决方案:
parallel mycommand {} -o {.}-processed.txt ::: *.txt
它将在后面获取一个字符串列表:::
(shell 将扩展*.txt
为匹配文件名的列表)并mycommand {} -o {.}-processed.txt
为每个字符串运行,替换{}
为输入字符串(就像xargs
)和{.}
不带扩展名的文件名。
您可以通过stdin
(参数find
-way),将其与or配对locate
,但我很少需要除了zsh
的扩展 glob 之外的任何东西。
看一眼GNU 并行教程了解它能做什么。我一直使用它进行批量转换、将档案提取到子目录等。
答案3
这适应了用户1404316的回答跟...共事find
:
find . -type f -name '*.txt' \
-exec sh -c 'for file do mycommand "$file" -o "${file%.txt}-processed.txt"; done' sh {} +
(您可以将所有内容都输入一行;只需省略\
。为了便于阅读,我将其分成两行。)
另一种格式化它以提高可读性的方法,使嵌入的 shell 脚本更加清晰:
find . -type f -name '*.txt' -exec sh -c '
for file
do
mycommand "$file" -o "${file%.txt}-processed.txt";
done
' sh {} +
基本上,它创建一个未命名的 shell 脚本:
for file
do
mycommand "$file" -o "${file%.txt}-processed.txt"
done
(这是单引号之间的字符串,'…'
展开)并将其作为命令 ( ) 传递到 shell,sh -c
并以所有文件的名称.txt
作为参数。 (通常不需要引用{}
,也不需要在 中使用花括号"$file"
。)
答案4
如果您需要递归和更复杂的字符串替换,则find
,sed
和的组合可能会起作用:xargs
find . -iname '*.txt' -printf "%p\0-o\0%p\0" | sed -z '3~3s/\.txt$/-processed&/' | xargs -0 -n 3 echo mycommand
例子:
$ find
.
./bar baz.txt
./foo.txt
$ find . -iname '*.txt' -printf "%p\0-o\0%p\0" | sed -z '3~3s/\.txt$/-processed&/' | xargs -0 -n 3 echo mycommand
mycommand ./bar baz.txt -o ./bar baz-processed.txt
mycommand ./foo.txt -o ./foo-processed.txt
该命令-printf "%p\0-o\0%p\0"
将文件路径打印两次,-o
中间用 ASCII NUL 字符分隔,并且该命令在每三行的尾随之前sed
插入一个。然后一次使用三个参数运行该命令,这将是文件名、和编辑的文件名。-processed
.txt
xargs
-o