对每个文件运行命令,并使用取决于文件名的标志参数

对每个文件运行命令,并使用取决于文件名的标志参数

假设我有一个文件夹,其中包含名称类似的文件

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}删除与模式匹配的最小后缀字符串(在本例中为扩展名),因此我们可以将其替换为您想要的后缀。barfoo.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.txtxargs-o

相关内容