使用 sed 在 bash 脚本中进行就地重命名
Posted
技术标签:
【中文标题】使用 sed 在 bash 脚本中进行就地重命名【英文标题】:Using sed to do an in-place rename in bash script 【发布时间】:2014-06-07 16:43:24 【问题描述】:我在 OSX 上有一个文件夹,其中包含从在线 DVR 下载的电视节目。我想制作一个程序列表并将其格式化以匹配另一个列表以进行比较。
当我在 shell 中运行以下命令时,一切正常,我得到了我想要的列表。
ls *.mp4 > loaded_shows.txt
sed -i$0 's/\(.*\)_/\1\ /' loaded_shows.txt
sed -i$0 's/\(.*\)_/\1\ /' loaded_shows.txt
sed -i$0 's/\(.*\)_/\1\ /' loaded_shows.txt
cat loaded_shows.txt
当我将相同的命令放入 bash 脚本时,即使脚本与文件位于同一目录中,sed 也会为每个就地替换提供以下错误消息。
sed: rename(): 没有这样的文件或目录
为了完整起见,这里是 bash 脚本:
#!/bin/bash
ls *.mp4 > loaded_shows.txt
sed -i$0 's/\(.*\)_/\1\ /' loaded_shows.txt # replace last _ with space
sed -i$0 's/\(.*\)_/\1\ /' loaded_shows.txt # again replace last _ with space
sed -i$0 's/\(.*\)_/\1\ /' loaded_shows.txt # remove the file extension
cat loaded_shows.txt
以及示例输入文件名:
666_Park_Avenue_2014-04-22_23.35.mp4
Americans_2014-04-20_22.45.mp4
Scandal_2014-04-20_21.00.mp4
The_Voice_of_USA_2014-04-22_19.30.mp4
如何让 sed 在 bash 脚本中工作?
【问题讨论】:
你是如何运行 Bash 脚本的?它仍然创建loaded_shows.txt吗? 我发现我做错了什么。问题在于 -i 参数的格式。我在某处看到了这个例子,没有进一步解释。我尝试了几种告诉 sed 不要备份文件的方法,而 -i$0 是我发现的唯一一个似乎适用于 OSX 的示例。在发布此问题后阅读更多内容后,我意识到 -i$0 在脚本中不起作用。我用 -i '' (之间的空格)替换了它,现在脚本可以工作并创建loaded_shows.txt。一些示例建议使用 -i''(之间没有空格),这在 OSX 上不起作用。 你打败了我。我建议-i .bak
作为论据。 $0
可能有用;它是脚本的名称,但如果它在$0
中有路径信息,你就完蛋了。
我遇到了同样的问题。我不需要备份文件 - 是的,我知道我在做什么 ;-)。 -i 之后的空格和两个双引号完成了这项工作:sed -e 's,2016-11-03.01,2016-11-03.02,g' -i ""
find src web -type f``
【参考方案1】:
您已经注意到 sed 的 -i
选项的错误。找到它做得很好。 :)
如果脚本中的 cmets 表明您要实现的目标,我实际上会重构脚本以在管道中使用 sed 一次,看起来像这样:
#!/bin/bash
for f in *.mp4; do
echo "$f" | sed 's/_\([^_]*\)_\([^_]*\).mp4$/ \1 \2/'
done > loaded_shows.txt
运行 sed 的次数越少越经济,而只打开/关闭文本文件一次会经济得多。因为,你知道,浪费一毫秒就是损失一毫秒。
我应该在这里指出for
循环。通常,当您在 shell 脚本中运行文件列表时,您希望使用 for
而不是解析 ls
的输出。 Parsing ls 是 shell 脚本世界中众所周知的问题,最好不要让自己养成这样的坏习惯,即使在受控环境中的小脚本中也是如此。
【讨论】:
您能否进一步优化:printf "%s\n" *.mp4 | sed 's/_\([^_]*\)_\([^_]*\).mp4$/ \1 \2/' > loaded_shows.txt
对所有文件名调用一次 sed?如果任何文件名包含换行符,它可能会遇到问题;否则,它应该是好的,我认为。您的版本每个文件名运行一次 sed;对于任意数量的文件,原始文件运行sed
三次(如果文件超过三个,则获胜;您的文件少于三个则获胜)。无论文件数量如何,我建议的修订版都会运行一次sed
。
非常感谢,这就像一个魅力,乔纳森的建议更加简化了脚本。我想知道如何更有效地进行 sed 替换,但我自己无法弄清楚。我知道足以替换一次出现,但是用一个命令替换三件事超出了我的知识范围。你们中的任何一个能否分解 sed,以便我了解 sed 在这些示例中的实际工作原理?以上是关于使用 sed 在 bash 脚本中进行就地重命名的主要内容,如果未能解决你的问题,请参考以下文章