我想通过命令行在 HTML 文件上运行查找和替换。
我的命令看起来像这样:
sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html > index.html
当我运行它并随后查看文件时,它是空的。它删除了我文件的内容。
当我再次恢复文件后运行它时:
sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html
stdout
是文件的内容,并且已经执行了查找和替换。
为什么会这样?
perl -pi -w -e 's/STRING_TO_REPLACE/REPLACE_WITH/g;' index.html
sed
命令来查找字符串并替换整行:stackoverflow.com/questions/11245144/…
当 shell 在命令行中看到 > index.html
时,它会打开文件 index.html
以进行 writing,擦除之前的所有内容。
要解决此问题,您需要将 -i
选项传递给 sed
以进行内联更改并在原地进行更改之前创建原始文件的备份:
sed -i.bak s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html
如果没有 .bak,该命令将在某些平台上失败,例如 Mac OSX。
另一种有用的模式是:
sed -e 'script script' index.html > index.html.tmp && mv index.html.tmp index.html
在不使用 -i
选项的情况下,效果大致相同,另外还意味着,如果 sed 脚本由于某种原因失败,则不会破坏输入文件。此外,如果编辑成功,则不会留下任何备份文件。这种习惯用法在 Makefile 中很有用。
很多 sed 都有 -i
选项,但不是全部; posix sed 不是。因此,如果您的目标是便携性,则最好避免。
... && mv index.html{.tmp,}
sh
(如果我没记错的话)没有那个 {...}
扩展。在 Makefile 中,您可能使用的是 sh
而不是 bash
,因此如果您的目标是可移植性(或 posixness),那么您需要避免这种结构。
sed -i 's/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' index.html
这会对文件 index.html 进行全局就地替换。引用字符串可以防止查询和替换中出现空格问题。
使用 sed 的 -i 选项,例如
sed -i bak -e s/STRING_TO_REPLACE/REPLACE_WITH/g index.html
's/STRING_TO_REPLACE/REPLACE_WITH/g'
-i
执行 files 的就地编辑,因此将其与 stdin 输入结合起来没有意义。
要更改多个文件(并将每个文件的备份保存为 *.bak):
perl -p -i -e "s/\|/x/g" *
将获取目录中的所有文件并将 |
替换为 x
这称为“Perl pie”(很简单)
sed
指定为要求,仅将其用作已经尝试过的工具。
您应该尝试使用选项 -i
进行就地编辑。
警告:这是一种危险的方法!它滥用 linux 中的 i/o 缓冲区,并通过特定的缓冲选项设法处理小文件。这是一个有趣的好奇心。但不要将其用于实际情况!
除了 sed
的 -i
选项外,您还可以使用 tee
实用程序。
从 man
:
tee - 从标准输入读取并写入标准输出和文件
因此,解决方案是:
sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee | tee index.html
-- 这里重复 tee
以确保管道被缓冲。然后管道中的所有命令都被阻塞,直到它们得到一些输入来处理。当上游命令将 1 个字节缓冲区(大小定义为 somewhere)写入命令的输入时,管道中的每个命令都会启动。所以最后一个命令 tee index.html
,它打开文件进行写入并因此清空它,在上游管道完成并且输出在管道内的缓冲区中之后运行。
以下很可能不起作用:
sed s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html | tee index.html
-- 它将同时运行管道的两个命令而没有任何阻塞。 (不阻塞管道应该逐行传递字节而不是逐缓冲区传递。与运行 cat | sed s/bar/GGG/
时相同。不阻塞它更具交互性,通常只有 2 个命令的管道在没有缓冲和阻塞的情况下运行。更长的管道被缓冲。 ) tee index.html
将打开文件进行写入,并将其清空。但是,如果您始终打开缓冲,则第二个版本也可以使用。
>
那样立即被截断,但重点是它是一个可能导致数据丢失的损坏解决方案)。
sed -i.bak "s#https.*\.com#$pub_url#g" MyHTMLFile.html
如果您有要添加的链接,请尝试此操作。搜索上述 URL(此处以 https 开头,以 .com 结尾)并将其替换为 URL 字符串。我在这里使用了变量 $pub_url
。这里的 s
表示搜索,g
表示全局替换。
有用 !
命令的问题
sed 'code' file > file
是 file
在 sed 实际处理它之前被 shell 截断。结果,您得到一个空文件。
正如其他答案所建议的那样,执行此操作的 sed 方法是使用 -i
进行就地编辑。但是,这并不总是您想要的。 -i
将创建一个临时文件,然后用于替换原始文件。如果您的原始文件是一个链接(该链接将被常规文件替换),这将是有问题的。如果需要保留链接,可以使用临时变量来存储 sed 的输出,然后再将其写回文件,如下所示:
tmp=$(sed 'code' file); echo -n "$tmp" > file
更好的是,使用 printf
而不是 echo
,因为在某些 shell(例如 dash)中,echo
可能会将 \\
处理为 \
:
tmp=$(sed 'code' file); printf "%s" "$tmp" > file
sed 'code' file > file.tmp; cat file.tmp > file; rm file.tmp
ed
答案:
printf "%s\n" '1,$s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g' w q | ed index.html
重申一下 codaddict answered,shell首先处理重定向,清除“input.html”文件,然后 然后shell 调用传递它的“sed”命令一个现在为空的文件。
sed
答案的“ed
版本”?它执行得更快吗?
sed
没有实现 -i
来就地编辑。 ed
无处不在,可以让您将编辑保存到原始文件。另外,在您的工具包中拥有很多工具总是好的。
printf "%s\n" '1,$s/^STRING_TO_REPLACE.*/$MODPATH/g' w q | ed $SERVICESH > /dev/null 2>&1
。我想将 $MODPATH 作为替换字符串传递,但无法使其工作
我正在寻找可以定义行范围并找到答案的选项。例如,我想将第 36-57 行的 host1 更改为 host2。
sed '36,57 s/host1/host2/g' myfile.txt > myfile1.txt
您也可以使用 gi 选项来忽略字符大小写。
sed '30,40 s/version/story/gi' myfile.txt > myfile1.txt
在充分尊重上述正确答案的情况下,像这样“试运行”脚本总是一个好主意,这样您就不会损坏文件并且必须从头开始重新开始。
只需让您的脚本将输出溢出到命令行而不是将其写入文件,例如,像这样:
sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g index.html
或者
less index.html | sed -e s/STRING_TO_REPLACE/STRING_TO_REPLACE_IT/g
这样您就可以查看和检查命令的输出,而不会截断您的文件。
truncates the file
而不是opens the file
可能会更清楚。sed -i '' 's/blah/xx/g'
sed -i
之后的.bak
是什么?