Answers:
以下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
/dir/
,则循环仍将使用'*'的值运行一次$file
,这可能是不希望的。为避免这种情况,请在循环期间启用nullglob。在循环之前添加此行,在循环shopt -s nullglob
之后添加此行shopt -u nullglob #revert nullglob back to it's normal default state
。
done >results.out
(可能然后您可以覆盖而不是像我在这里假设的追加)。
这个怎么样:
find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out
-maxdepth 1
参数防止find递归地降级到任何子目录中。(如果要处理此类嵌套目录,则可以省略。)-type -f
指定仅将处理纯文件。-exec cmd option {}
告诉它以找到的每个文件cmd
的指定名称运行option
,并用文件名替换{}
\;
表示命令的结尾。cmd
执行的输出都重定向到
results.out
但是,如果您关心文件的处理顺序,则最好编写循环。我认为find
按inode顺序处理文件(尽管我可能对此有误),这可能不是您想要的。
stat
和)来完成排序sort
,哪个过程取决于什么是排序标准。
-exec
选项后如何链接它们?我是否必须将它们用单引号引起来?
find
始终是最好的选择,因为您可以使用option按文件名模式进行过滤,-name
并且可以在单个命令中进行操作。
-exec
选项:find . -name "*.txt" -exec echo {} \; -exec grep banana {} \;
公认的/高投票的答案很好,但是它们缺少一些实质性的细节。这篇文章介绍了以下情况:如何更好地处理shell路径名扩展(glob)失败,文件名包含嵌入式换行符/破折号以及将结果输出重定向到for循环时(将结果写入a时)的情况。文件。
当使用shell运行glob扩展时*
,如果目录中没有文件,则扩展可能会失败,并且未扩展的glob字符串将传递给要运行的命令,这可能会导致不良结果。所述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
不会随后运行的循环。
还要注意--
在传递文件名参数之前的用法。这是必需的,因为如前所述,shell文件名可以在文件名中的任何地方包含短划线。一些shell命令会对此进行解释,并在名称未正确引用时将其视为命令选项,并考虑是否提供了标志来执行命令。
该--
信号在这种情况下,该装置的命令行选项结束时,命令不能解析超过此点作为命令标志但仅作为文件名的任何字符串。
将文件名双引号可以正确解决名称中包含全局字符或空格的情况。但是* nix文件名中也可以包含换行符。因此,我们使用唯一不能包含在有效文件名中的字符来分隔文件名-空字节(\0
)。由于bash
内部使用C
样式字符串,其中使用空字节来指示字符串的结尾,因此,它是正确的选择。
因此,使用printf
shell -d
选项通过read
命令option 使用此NULL字节定界文件,我们可以执行以下操作
( shopt -s nullglob; printf '%s\0' ./* ) | while read -rd '' file; do
cmdToRun [option] -- "$file"
done
在nullglob
与printf
被缠(..)
他们基本上在一个子shell(子shell)运行,这意味着,避免因为nullglob
反思父shell,一旦命令退出选项。该-d ''
的选项read
命令是不符合POSIX标准,所以需要一个bash
壳为此做。使用find
命令可以做到这一点
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0)
对于find
不支持的实现-print0
(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
基本上,每次输入文件的迭代时,命令的内容都会放入stdout中,当循环结束时,打开目标文件一次,以写入stdout的内容并保存。find
相同的等效版本是
while IFS= read -r -d '' file; do
cmdToRun [option] -- "$file"
done < <(find -maxdepth 1 -type f -print0) > results.out
一种有时可以完成工作的快速而肮脏的方法是:
find directory/ | xargs Command
例如,要查找当前目录中所有文件的行数,可以执行以下操作:
find . | xargs wc -l
~/.local/share/steam
steam。它删除了用户拥有的系统上的所有内容”之类的东西结束。错误报告。
我需要将所有.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;
对于模式中的每个文件
mkdir -p ../docs/"$i"
在包含文件的文件夹之外的docs文件夹中创建该目录。这将创建一个与该文件同名的额外文件夹。
rm -r ../docs/"$i"
删除由于以下原因而创建的多余文件夹 mkdir -p
cp "$i" "../docs/$i"
复制实际文件
echo "$i -> ../docs/$i"
回声你做了什么
; done
从此过上幸福的生活
**
要工作,globstar
需要设置外壳选项:shopt -s globstar
基于@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
-print0
的find
和-0
为xargs
它们使用空字符,而不是任何空白(包括换行)。
-print0
是有帮助的,但是整个管道都需要使用类似的东西,而sort
不是
我发现它与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
ls <directory> | xargs cmd [options] {filenames put in here automatically by xargs} [more arguments] > results.out