这有效:
sudo sed 's/good times/bad times/' Chapter1.html > output/Chapter1.html
这不起作用:
sudo sed 's/good times/bad times/' Chapter*.html > output/Chapter*.html
这也不起作用:
sudo sed 's/good times/bad times/' *.html > output/*.html
由于有五十章,我可以让 sed 使用通配符吗?
答案1
正如其他人评论的那样,这需要一个循环,而不仅仅是通配符。
例如,要使用 shellfor
循环执行此操作:
for f in ./*.html; do
sed 's/good times/bad times/' "$f" > "output/$f"
done
这依次将变量设置f
为每个 .html 文件名,为循环的每次迭代执行循环内的代码。请参阅下文了解为什么我使用./*.html
而不是仅使用*.html
.
f
请注意它在语句本身中如何具有裸字for
(因为这是它设置值的地方),但是$f
当变量在循环内部使用时(因为这是它被扩展的地方)。
变量扩展也用双引号引起来,以确保它们不会破坏脚本(或更糟),如果它们碰巧包含空白字符或对 shell 有特殊含义的其他字符(例如;
、&
、>
和许多其他的)。使用变量时未能引用变量可能是 shell 脚本错误的首要原因。看为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?和$VAR 与 ${VAR} 以及引用或不引用了解原因。
您可以使用您喜欢的任何变量名称,例如
for Chapter in ./*.html; do
sed 's/good times/bad times/' "$Chapter" > "output/$Chapter"
done
另外值得注意的是:如果目录中没有 .html 文件,shell 会将f
(或Chapter
) 设置为文字字符串,*.html
除非您首先使用 开启该nullglob
选项shopt -s nullglob
。从man bash
:
nullglob
如果设置,bash 允许不匹配任何文件的模式(请参阅
上面的路径名扩展)扩展为空字符串,而不是它们本身。
顺便说一句,我./*.html
与for
循环一起使用,而不仅仅是*.html
为了防止文件名sed
被解释为命令行选项之一。
正如 @StéphaneChazelas 在评论中提到的,如果目录中存在以 开头-e
和结尾的文件名,sed 会将其解释为要执行的 sed 脚本。#.html
这种情况不太可能发生(但是排泄物会发生,恶意也会发生),但最好尽可能地进行防御性编程。
通过使用./*.html
,而不是 sed 看到一个参数,例如,-e1,$d
由于名为-e1,$d#.html
(这是一个完全有效的文件名)的文件,它看到的参数./-e1,$d
不会被解释为 sed 的命令行选项之一...sed 的选项不以./
.
另外:因为$f
以 开头./
,因此文件名之类的输出foo.html
将被重定向到output/./foo.html
.这完全没问题,./
路径中有额外的元素仍然解析到相同的目的地。即使是荒谬的事情也output/./././[a million more ./s]/foo.html
只是output/foo.html
如果您使用 GNU sed(这是 linux 上的标准 sed)或(几乎?)任何现代版本的 sed,您可以使用 来--
指示选项参数的结束:
for f in *.html; do
sed 's/good times/bad times/' -- "$f" > "output/$f"
done
或者两者都做:
for f in ./*.html; do
sed 's/good times/bad times/' -- "$f" > "output/$f"
done
答案2
shell 在命令行上扩展通配符,而正在运行的命令既看不到它们也不知道如何处理它们。
所以如果你有文件a.html
b.html
并且output/b.html
output/c.html
你运行了
sed ... *.html > output/*.html
实际运行的命令是
sed ... a.html b.html > output/b.html output/c.html
这是一个语法错误(无法重定向到两个文件)并且与您可能想要的完全不一样。
这里的解决方案是使用 for 循环并将 * 替换为循环的索引变量。如果任何文件名中有空格,则需要进行一些引用。在这个问题的副本中,有很多关于如何正确执行此操作的示例。
答案3
假设您位于包含文件的工作目录中,您可以使用find
$ find . -name 'Chapter*' -exec sed 's/good times/bad times/woutput/{}' {} 2> /dev/null \;