有人可以提供代码来执行以下操作:假设有一个文件目录,所有这些都需要通过程序运行.程序将结果输出到标准输出.我需要一个脚本进入目录,在每个文件上执行命令,并将输出连接成一个大输出文件.
例如,要在1个文件上运行该命令:
$ cmd [option] [filename] > results.out
Run Code Online (Sandbox Code Playgroud)
And*_*nov 380
以下bash代码将$ file传递给命令,其中$ file将表示/ dir中的每个文件
for file in /dir/*
do
cmd [option] "$file" >> results.out
done
Run Code Online (Sandbox Code Playgroud)
例
el@defiant ~/foo $ touch foo.txt bar.txt baz.txt
el@defiant ~/foo $ for i in *.txt; do echo "hello $i"; done
hello bar.txt
hello baz.txt
hello foo.txt
Run Code Online (Sandbox Code Playgroud)
Jim*_*wis 160
这个怎么样:
find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out
Run Code Online (Sandbox Code Playgroud)
-maxdepth 1
参数阻止查找以递归方式递减到任何子目录中.(如果要处理这样的嵌套目录,可以省略它.)-type -f
指定仅处理纯文本.-exec cmd option {}
告诉它cmd
使用指定option
的每个文件运行,并替换文件名{}
\;
表示命令的结束.cmd
执行的输出都被重定向到
results.out
但是,如果您关心文件的处理顺序,那么编写循环可能会更好.我认为find
以inode顺序处理文件(虽然我可能错了),这可能不是你想要的.
rob*_*ves 47
我通过运行命令行在我的覆盆子pi上执行此操作:
for i in *;do omxplayer "$i";done
Run Code Online (Sandbox Code Playgroud)
Ini*_*ian 10
接受/高投票的答案很好,但它们缺乏一些细节。这篇文章介绍了如何更好地处理 shell 路径名扩展 (glob) 失败、文件名包含嵌入的换行符/破折号以及将命令输出重定向移出 for 循环时将结果写入到文件。
使用运行 shell glob 扩展时*
,如果目录中没有文件,则扩展可能会失败,并且未扩展的 glob 字符串将传递给要运行的命令,这可能会产生不良结果。所述bash
外壳提供了用于此使用扩展壳选项nullglob
。所以循环在包含文件的目录中基本上变成如下
shopt -s nullglob
for file in ./*; do
cmdToRun [option] -- "$file"
done
Run Code Online (Sandbox Code Playgroud)
这使您可以在表达式./*
不返回任何文件时安全地退出 for 循环(如果目录为空)
或以符合 POSIX 的方式(nullglob
是bash
特定的)
for file in ./*; do
[ -f "$file" ] || continue
cmdToRun [option] -- "$file"
done
Run Code Online (Sandbox Code Playgroud)
这使您可以在表达式失败一次时进入循环,并且条件[ -f "$file" ]
检查未扩展的字符串./*
是否是该目录中的有效文件名,而事实并非如此。因此,在这种情况下失败时,使用continue
我们恢复到for
随后不会运行的循环。
还要注意--
传递文件名参数之前的用法。这是必需的,因为如前所述,shell 文件名可以在文件名的任何位置包含破折号。当名称未正确引用并执行命令时,某些 shell 命令会解释它并将它们视为命令选项,并考虑是否提供了标志。
--
在这种情况下,该信号表示命令行选项的结束,这意味着该命令不应将超出此点的任何字符串解析为命令标志,而只能解析为文件名。
双引号正确地解决了文件名包含全局字符或空格的情况。但是 *nix 文件名中也可以包含换行符。因此,我们使用唯一不能作为有效文件名一部分的字符(空字节 ( \0
))来限制文件名。由于bash
内部使用C
样式字符串,其中空字节用于指示字符串的结尾,因此它是正确的候选者。
所以使用printf
shell的-d
选项使用read
command的选项来用这个NULL字节分隔文件,我们可以在下面做
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done
Run Code Online (Sandbox Code Playgroud)
在nullglob
与printf
被缠(..)
他们基本上在一个子shell(子shell)运行,这意味着,避免因为nullglob
反思父shell,一旦命令退出选项。命令的-d ''
选项不符合 POSIX 标准,因此需要一个shell 来完成。使用命令可以这样做read
bash
find
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)
Run Code Online (Sandbox Code Playgroud)
对于find
不支持的实现-print0
(除了 GNU 和 FreeBSD 实现),这可以使用printf
find . -maxdepth 1 -type f -exec printf '%s\0' {} \; | xargs -0 cmdToRun [option] --
Run Code Online (Sandbox Code Playgroud)
另一个重要的修复是将重定向移出 for 循环以减少大量文件 I/O。当在循环内使用时,shell 必须为 for 循环的每次迭代执行两次系统调用,一次用于打开,一次用于关闭与文件关联的文件描述符。这将成为运行大型迭代的性能瓶颈。推荐的建议是将它移到循环之外。
使用此修复程序扩展上述代码,您可以这样做
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done > results.out
Run Code Online (Sandbox Code Playgroud)
这基本上会将文件输入的每次迭代的命令内容放入标准输出,当循环结束时,打开目标文件一次以写入标准输出的内容并保存它。find
相同的等效版本是
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out
Run Code Online (Sandbox Code Playgroud)
您可以使用xarg
:
ls | xargs -L 1 -d '\n' your-desired-command
Run Code Online (Sandbox Code Playgroud)
-L 1
导致一次通过 1 个项目
-d '\n'
ls
根据新行拆分输出。
有时完成工作的一种快速而肮脏的方法是:
find directory/ | xargs Command
Run Code Online (Sandbox Code Playgroud)
例如要查找当前目录中所有文件的行数,您可以执行以下操作:
find . | xargs wc -l
Run Code Online (Sandbox Code Playgroud)