例如,在1个文件上运行命令:
$ cmd [option] [filename] > results.out
这个怎么样:
find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out
-maxdepth 1
-type -f
-exec cmd option {}
cmd
option
{}
\;
results.out
然而,如果您关心文件处理的顺序,您可以使用 也许写个循环会更好。我认为find处理文件 在inode顺序(虽然我可能是错的),这可能不是什么 你想要的。< / p >
find
下面的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
我在树莓派的命令行中运行:
for i in *; do cmd "$i"; done
我需要将所有.md文件从一个目录复制到另一个目录,下面是我所做的。
for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done
这很难读,所以让我们分解一下。
第一张CD放入你的文件目录,
for i in **/*.md;为你的模式中的每个文件
for i in **/*.md;
mkdir -p ../docs/"$i"make该目录在docs文件夹外的文件夹包含你的文件。这将创建一个与该文件同名的额外文件夹。
mkdir -p ../docs/"$i"
rm -r ../docs/"$i"删除由于mkdir -p而创建的额外文件夹
rm -r ../docs/"$i"
mkdir -p
cp "$i" "../docs/$i"复制实际文件
cp "$i" "../docs/$i"
echo "$i -> ../docs/$i"回声你做了什么
echo "$i -> ../docs/$i"
从此过上幸福的生活
一种快速而肮脏的方法有时可以完成工作:
find directory/ | xargs Command
例如,要查找当前目录中所有文件的行数,您可以这样做:
find . | xargs wc -l
公认的/高投票的答案是很好的,但他们缺乏一些本质的细节。这篇文章涵盖了如何更好地处理当shell路径名展开(glob)失败时,当文件名包含嵌入的换行符/破折号时,以及在将结果写入文件时将命令输出重定向移出for循环的情况。
当使用*运行shell glob扩展时,如果目录中存在没有文件,那么扩展可能会失败,并且将未展开的glob字符串传递给要运行的命令,这可能会产生不希望看到的结果。bash shell使用nullglob提供了一个扩展的shell选项。因此,在包含文件的目录中,循环基本上如下所示
*
bash
nullglob
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循环,该循环随后不会运行。
[ -f "$file" ]
continue
for
还要注意在传递文件名参数之前使用--。这是必需的,因为如前所述,shell文件名可以在文件名中的任何位置包含破折号。一些shell命令解释了这一点,当名称不被正确引用时,将它们视为命令选项,如果提供了标志,则执行命令思维。
--
在这种情况下,--标志着命令行选项的结束,这意味着命令不应该将超出这一点的任何字符串解析为命令标志,而只能将其解析为文件名。
文件名的双引号可以正确地解决名称包含glob字符或空格的情况。但是*nix文件名也可以包含换行符。因此,我们用唯一不能成为有效文件名一部分的字符来限制文件名——空字节(\0)。由于bash内部使用C样式的字符串,其中null字节用于表示字符串的结束,因此它是正确的候选对象。
\0
C
因此,使用shell的printf选项,使用read命令的-d选项,用这个NULL字节分隔文件,我们可以执行以下操作
printf
read
-d
( 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命令可以这样做
(..)
-d ''
while IFS= read -r -d '' file; do cmdToRun [option] -- "$file" done < <(find -maxdepth 1 -type f -print0)
对于不支持-print0的find实现(除了GNU和FreeBSD实现),可以使用printf来模拟
-print0
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
这将基本上将您的文件输入的每次迭代的命令内容放到标准输出中,当循环结束时,打开目标文件一次以写入标准输出的内容并保存它。等价的find版本的same将是
while IFS= read -r -d '' file; do cmdToRun [option] -- "$file" done < <(find -maxdepth 1 -type f -print0) > results.out
我认为简单的解决方法是:
sh /dir/* > ./result.txt
我发现它在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:
xarg
ls | xargs -L 1 -d '\n' your-desired-command
-L 1导致每次传递一个项
-L 1
-d '\n'根据换行拆分ls的输出。
-d '\n'
ls