我的任务的挑战是可以file.txt
位于子文件夹或子子文件夹中。一般结构如下:
folder
|___subfolder
|_____file.txt
|
|___subfolder
|____subfolder
|_______file.txt
etc
我之前的代码不处理子子文件夹,我不知道如何添加这部分(因为某些子文件夹没有任何后续文件夹)
for dir in ./*/ ; do
if [ -d "$dir" ]; then
cd $d;
for subdir in ./*/; do
cd $subdir && $(sed command file.txt) && cd ..;
done
cd ..
fi
done
我还了解到有一种使用的单行方法find
,例如:
find . -name 'file.txt' | sed command file.txt
显然这个不起作用,因为find
只能将目录返回到我的file.txt
答案1
尝试:
find . -name 'file.txt' -exec sed command {} +
file.txt
这将查找子目录中名为该文件的所有文件,并针对这些文件.
运行。sed command
如果您想sed
就地修改这些文件,请添加该-i
选项。
虽然-exec ... +
现在需要POSIX(提示:jordanm),有些人可能正在使用find
不支持+
.如果您有其中之一,请使用(帽子提示:unxnut):
find . -name 'file.txt' -exec sed command {} \;
更安全的选择
如果对目录结构进行快速更改,-exec
则可能会出现竞争条件。为了提高安全性,请使用-execdir
(帽子提示:unxnut):
find . -name 'file.txt' -execdir sed command {} +
请注意,如果您的 中有当前目录PATH
,-execdir
则将拒绝运行。
答案2
除非您知道该sed
命令在做什么,否则您希望sed
每个输入文件运行一个命令。
您可以使用for
循环来完成此操作(如果您的 shell 支持递归通配符),例如zsh
、ksh93
、yash
、bash
(tcsh
以及fish
,但循环语法不同)。
shopt -s globstar # bash
#set -o globstar # ksh93
#set -o extended-glob # yash
for f in **/file.txt; do [ -f "$f" ] && sed 'cmd' "$f"; done
或(正如其他人指出的)find
:
find . -type f -name 'file.txt' -exec sed 'cmd' {} \;
现在,有人可能想知道 - 为什么不“优化”这一点并将find
s-exec
与+
或 a zsh
-ism 一起使用,例如:
sed 'cmd' **/file.txt(.)
当然,这些会更有效,因为它们调用sed
多个文件操作数但是那很可能存在问题:
为了简单起见,假设您尝试使用命令sed
11q
仅打印每个文件的第一行(不就地编辑文件2,也许将组合输出重定向到另一个文件或只是检查它)所以你可以运行
find . -name 'file.txt' -exec sed '1q' {} +
或者
sed '1q' **/file.txt(.)
然而他们都将无法交付,因为
如果指定了多个文件操作数,则应按指定的顺序读取指定的文件并编辑连接
因此,sed
只会打印输入的第一行,而不是每个文件3的第一行。
现在,gnu sed
有-s
开关:
-s, --separate
consider files as separate rather than as a single continuous long stream
有时这可能会派上用场,但在这种特殊情况下(1q
),它没有帮助。
1:如果你不喜欢1q
尝试$d
,应该删除每个文件的最后一行2:有时你可能会像暗示的那样
逃脱,但绝对不是当命令之一是gnu sed
-i
-s
sed
q
3:你可能会争辩说这是因为q
退出 - 但是如果你使用sed -n '1p'
- 我只q
强调 2,也会发生同样的情况:
答案3
假设您的文件路径不包含空格、换行符、单引号、双引号或反斜杠字符:
find . -name 'file.txt' -type f | xargs sed command