有人能提供代码来做以下工作吗: 假设有一个文件目录,所有这些文件都需要通过一个程序运行。程序将结果输出到标准输出。我需要一个脚本,它将进入一个目录,对每个文件执行命令,并将输出连接到一个大输出文件。
例如,在1个文件上运行命令:
$ cmd [option] [filename] > results.out
有人能提供代码来做以下工作吗: 假设有一个文件目录,所有这些文件都需要通过一个程序运行。程序将结果输出到标准输出。我需要一个脚本,它将进入一个目录,对每个文件执行命令,并将输出连接到一个大输出文件。
例如,在1个文件上运行命令:
$ cmd [option] [filename] > results.out
这个怎么样:
find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out
-maxdepth 1参数防止find函数递归降为 任何子目录。(如果你想处理这样的嵌套目录,你可以省略这个。) -type -f指定只处理普通文件。 -exec CMD选项{}告诉它对找到的每个文件使用指定选项运行CMD,文件名替换为{} \;表示命令的结束。 最后,所有单个cmd执行的输出被重定向到 results.out
但是,如果您关心文件处理的顺序,则可以使用 也许写个循环会更好。我认为find处理文件 在inode顺序(虽然我可能是错的),这可能不是什么 你想要的。
下面的bash代码将把$file传递给命令,其中$file将表示/dir中的每个文件
for file in /dir/*
do
cmd [option] "$file" >> results.out
done
例子
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
基于@Jim Lewis的方法:
下面是一个使用find并按修改日期对文件进行排序的快速解决方案:
$ find directory/ -maxdepth 1 -type f -print0 | \
xargs -r0 stat -c "%y %n" | \
sort | cut -d' ' -f4- | \
xargs -d "\n" -I{} cmd -op1 {}
排序参见:
http://www.commandlinefu.com/commands/view/5720/find-files-and-list-them-sorted-by-modification-time
我需要将所有.md文件从一个目录复制到另一个目录,下面是我所做的。
I在**/*.md;执行mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i";完成
这很难读,所以让我们分解一下。
第一张CD放入你的文件目录,
对于I在**/*.md;对于模式中的每个文件
Mkdir -p ../docs/"$i"把这个目录放在包含你的文件的文件夹外的docs文件夹中。这将创建一个与该文件同名的额外文件夹。
Rm -r ../docs/"$i"删除mkdir -p创建的额外文件夹
Cp "$i" "..复制实际文件
Echo“$i -> ..”/docs/$i" Echo你所做的
; 从此过上幸福的生活
一种快速而肮脏的方法有时可以完成工作:
find directory/ | xargs Command
例如,要查找当前目录中所有文件的行数,您可以这样做:
find . | xargs wc -l
公认的/高投票的答案是很好的,但他们缺乏一些本质的细节。这篇文章涵盖了如何更好地处理当shell路径名展开(glob)失败时,当文件名包含嵌入的换行符/破折号时,以及在将结果写入文件时将命令输出重定向移出for循环的情况。
当使用*运行shell glob扩展时,如果目录中没有文件,那么扩展可能会失败,并且将未展开的glob字符串传递给要运行的命令,这可能会产生不希望看到的结果。bash shell使用nullglob提供了一个扩展的shell选项。因此,在包含文件的目录中,循环基本上如下所示
shopt -s nullglob
for file in ./*; do
cmdToRun [option] -- "$file"
done
这样当表达式./*不返回任何文件(如果目录为空)时,可以安全地退出for循环。
或者以POSIX兼容的方式(nullglob是特定于bash的)
for file in ./*; do
[ -f "$file" ] || continue
cmdToRun [option] -- "$file"
done
这让您在表达式失败一次时进入循环,并且条件[-f "$file"]检查未展开的字符串./*是否是该目录中的有效文件名,但事实并非如此。在这种失败的情况下,使用continue,我们恢复到for循环,它随后不会运行。
还要注意在传递文件名参数之前使用的——。这是必需的,因为如前所述,shell文件名可以在文件名中的任何位置包含破折号。一些shell命令对此进行解释,并在名称未正确引用时将其视为命令选项,并在提供标志时执行命令思维。
在这种情况下,——标志命令行选项的结束,这意味着命令不应该将超出这一点的任何字符串解析为命令标志,而只能将其解析为文件名。
文件名的双引号可以正确地解决名称包含glob字符或空格的情况。但是*nix文件名也可以包含换行符。因此,我们用唯一不能成为有效文件名一部分的字符来限制文件名——空字节(\0)。由于bash内部使用C样式字符串,其中使用null字节表示字符串的结束,因此它是合适的候选对象。
因此,使用shell的printf选项使用read命令的-d选项用这个NULL字节分隔文件,我们可以执行以下操作
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done
nullglob和printf被包裹在(..)周围,这意味着它们基本上是在子shell(子shell)中运行的,因为为了避免一旦命令退出,nullglob选项就会反映到父shell上。read命令的-d "选项不符合POSIX,因此需要bash shell来完成此操作。使用find命令可以这样做
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)
对于不支持-print0的find实现(GNU和FreeBSD实现除外),可以使用printf来模拟
find . -maxdepth 1 -type f -exec printf '%s\0' {} \; | xargs -0 cmdToRun [option] --
另一个重要的修复是将重定向移出for循环,以减少大量的文件I/O。当在循环内部使用时,shell必须为for循环的每次迭代执行两次系统调用,一次用于打开与文件相关的文件描述符,一次用于关闭。这将成为运行大型迭代时性能的瓶颈。建议将其移到循环之外。
您可以使用此修复扩展上面的代码
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done > results.out
这将基本上将您的文件输入的每次迭代的命令内容放到标准输出中,当循环结束时,打开目标文件一次以写入标准输出的内容并保存它。等价的查找版本是
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out
Maxdepth
我发现它很适合Jim Lewis的答案,只需要添加一点这样的内容:
$ export DIR=/path/dir && cd $DIR && chmod -R +x *
$ find . -maxdepth 1 -type f -name '*.sh' -exec {} \; > results.out
排序顺序
如果你想按排序顺序执行,可以这样修改:
$ export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -maxdepth 2 -type f -name '*.sh' | sort | bash > results.out
举个例子,它将按照以下顺序执行:
bash: 1: ./assets/main.sh
bash: 2: ./builder/clean.sh
bash: 3: ./builder/concept/compose.sh
bash: 4: ./builder/concept/market.sh
bash: 5: ./builder/concept/services.sh
bash: 6: ./builder/curl.sh
bash: 7: ./builder/identity.sh
bash: 8: ./concept/compose.sh
bash: 9: ./concept/market.sh
bash: 10: ./concept/services.sh
bash: 11: ./product/compose.sh
bash: 12: ./product/market.sh
bash: 13: ./product/services.sh
bash: 14: ./xferlog.sh
无限的深度
如果你想在特定条件下无限深度执行,你可以使用这个:
export DIR=/path/dir && cd $DIR && chmod -R +x *
find . -type f -name '*.sh' | sort | bash > results.out
然后把子目录中的每个文件放在上面,就像这样:
#!/bin/bash
[[ "$(dirname `pwd`)" == $DIR ]] && echo "Executing `realpath $0`.." || return
在父文件主体的某个地方:
if <a condition is matched>
then
#execute child files
export DIR=`pwd`
fi
你可以使用xarg:
ls | xargs -L 1 -d '\n' your-desired-command
-L 1导致一次传递一个项目 -d '\n'根据换行拆分ls的输出。