如何通过替换文件名中的字符串来重命名多个文件?该字符串包含“#”


42

https://serverfault.com/questions/70939/how-to-replace-a-text-string-in-multiple-files-in-linux

https://serverfault.com/questions/228733/how-to-rename-multiple-files-by-replacing-word-in-file-name

https://serverfault.com/questions/212153/replace-string-in-files-with-certain-file-extension

https://serverfault.com/questions/33158/searching-a-number-of-files-for-a-string-in-linux

这些提到的文章都回答了我的问题。但是他们都不适合我。我怀疑是因为我要替换的字符串中包含#。有没有解决此问题的特殊方法?

我有一个图像文件,它在站点迁移期间将é替换为#U00a9。这些看起来像这样:

Lucky-#U00a9NBC-80x60.jpg
Lucky-#U00a9NBC-125x125.jpg
Lucky-#U00a9NBC-150x150.jpg
Lucky-#U00a9NBC-250x250.jpg
Lucky-#U00a9NBC-282x232.jpg
Lucky-#U00a9NBC-300x150.jpg
Lucky-#U00a9NBC-300x200.jpg
Lucky-#U00a9NBC-300x250.jpg
Lucky-#U00a9NBC-360x240.jpg
Lucky-#U00a9NBC-400x250.jpg
Lucky-#U00a9NBC-430x270.jpg
Lucky-#U00a9NBC-480x240.jpg
Lucky-#U00a9NBC-600x240.jpg
Lucky-#U00a9NBC-600x250.jpg
Lucky-#U00a9NBC.jpg

我想将其更改为以下内容:

Lucky-safeNBC-80x60.jpg
Lucky-safeNBC-125x125.jpg
Lucky-safeNBC-150x150.jpg
Lucky-safeNBC-250x250.jpg
Lucky-safeNBC-282x232.jpg
Lucky-safeNBC-300x150.jpg
Lucky-safeNBC-300x200.jpg
Lucky-safeNBC-300x250.jpg
Lucky-safeNBC-360x240.jpg
Lucky-safeNBC-400x250.jpg
Lucky-safeNBC-430x270.jpg
Lucky-safeNBC-480x240.jpg
Lucky-safeNBC-600x240.jpg
Lucky-safeNBC-600x250.jpg
Lucky-safeNBC.jpg

更新:

这些示例都以“ LU00a9ucky”开头,但是这里有许多名称不同的图像。我只是将字符串的“#U00a9”部分定位为“ safe”。


3
那么,您实际上尝试了什么?我看到您已经链接到几个问题,并说它们失败了,但是它们是怎么失败的呢?IMO最好的例子是使用rename命令。我怀疑您的重命名会很简单rename -n 's/#/safeNBC/' *.jpg
Zoredache 2014年

我尝试过rename -n 's/#U00a9/safe/' *.jpg并接受了命令,但未发生任何更改。

当然,正如您从您肯定会查看的文档中所看到的那样,-nno act选项是可行的。通过它,您可以在实际使用前查看它是否有效。屏幕上的输出是否正确显示了潜在的新名称?
Zoredache 2014年

抱歉,我没有完全注意就复制并粘贴了您的示例,我做了没有-n的重命名命令。我相信@DTK解决了这个问题,我没有逃脱#。

在Mac OS中的文件名更换字符串:superuser.com/questions/152627/...
安东塔拉先科

Answers:


64

要更换#somethingelse在当前目录下(不递归),你可以使用文件名GNU重命名工具:

rename  's/#/somethingelse/' *

像这样的字符-必须用进行转义\

对于您的情况,您想使用

rename 's/#U00a9/safe/g' *

请注意,如果您只想操作某个选择的文件,例如only *.jpg,请调整最终输入以匹配该选择:

rename 's/#U00a9/safe/g' *.jpg

要在实际更改文件名之前执行测试,请使用-n标志:

demo/> ls                               
Lucky-#U00a9NBC-125x125.jpg  
Lucky-#U00a9NBC-150x150.jpg 

demo/> rename -n 's/#U00a9/safe/g' *.jpg
rename(Lucky-#U00a9NBC-125x125.jpg, Lucky-safeNBC-125x125.jpg)
rename(Lucky-#U00a9NBC-150x150.jpg, Lucky-safeNBC-150x150.jpg)

对于OS X,可以使用homebrew:安装GNU重命名brew install rename


这在我的机器(Arch Linux)上不起作用,但是mik的答案起作用了。
marcvangend '17

@marcvangend rename您使用的是哪个版本? # sudo pacman -S perl-rename将安装perl版本,该版本功能更强大,可能足以使此答案对您有用。
约翰·高尔斯

@JohnGowers谢谢!我没有意识到有两个版本。在我的系统上,rename --version返回rename from util-linux 2.29.2值的确不是perl版本。
marcvangend

5
有两种常用的rename实用程序,但是它们都不是由GNU开发的:基于Debian的发行版包括一个rename带有Perl软件包的实用程序,而基于Red Hat的发行版则使用Linux Kernel Organization中的rename实用程序util-linux。您的链接是来自GNU标准库的renameC 函数
安东尼G-莫妮卡的大法官

2
在这个答案,我们为什么必须写/grename 's/#U00a9/safe/g' *
尼基尔

21

找到文件列表,然后替换关键字。以下是示例

find . -name '*jpg' -exec bash -c ' mv $0 ${0/\#U00a9NBC/safeNBC}' {} \;

1
如果mv名称中有空格,则需要在参数周围加上双引号
停止Harming Monica

我需要将所有文件* _spec.rb替换为* _controller_spec.rb,您的解决方案对我有用。谢谢
绝地

18

这并不难,只需确保通过在名称前面加上反斜杠(\)来使名称中的八字形(#)逸出即可。

find . -type f -name 'Lucky-*' | while read FILE ; do
    newfile="$(echo ${FILE} |sed -e 's/\\#U00a9/safe/')" ;
    mv "${FILE}" "${newfile}" ;
done 

您的解释很有道理,#就像我需要的那样转义。在您的示例中,我看不到反斜线。它应该是这样的: s/\#U00a9/safe/

@LeonFrancisShelhamer好收获。它吞下了反斜杠。我会修改。

17

要摆脱#外壳,只需使用单引号('#'),双引号("#")或反斜杠(\#)。

在您的情况下,最简单的方法是使用rename命令(如果可用):

rename '#U00a9' safe *.jpg

2
谢谢。尽管投票最高的答案(rename 's/#/somethingelse/' *)在我的计算机(Arch Linux)上不起作用,但该命令却可以。
marcvangend

1
使用util-linux中的重命名命令可以正常工作。
干净

10

不确定如何使用sed,但是您可以在bash shell中尝试使用此方法:

for f in Lucky-#U00a9NBC-*.jpg; do mv -v "$f" "${f/#U00a9/safe}"; done;

说明:

  1. 循环遍历与glob匹配的所有文件名(Lucky-#U00a9NBC-*。jpg)
  2. 使用move命令重命名文件(mv)
  3. 使用本地bash参数替换$ {var / Pattern / Replacement}来制作新名称(“ $ {f /#U00a9 / safe}”)

有关参数替换的更多信息(IMO的利用率极低):http : //www.tldp.org/LDP/abs/html/parameter-substitution.html


虽然这段代码可以回答这个问题,但它本身并不是很有用。解释它如何解决问题将提高答案的实用性和长期价值。
安东尼G-莫妮卡(Monica)的正义

根据Anthony的评论添加了演练说明和进一步阅读。
格雷戈里·帕特莫尔

1

上面的示例在我的系统(CentOS 5.6)上不起作用,因此我发现了一个有效的(可能是特定于系统的)命令(注意:需要\在命令行上使用'#'转义):

rename \#U00a9 safe *.jpg

[[另外:我还没有足够的声誉来发表评论,因此,为了回应Nikhil关于/gin 的使用的问题rename 's/old_string/new_string/g'(在上面的另一个答案的评论中提出):

使用g修饰符执行“全局”替换(即,在出现old_string时,用new_string替换old_string多次)。在我的回答中,这不是必需的,因为rename将会应用于用指定的所有文件*。有关此修饰符和其他修饰符的简要说明,请参见https://www.computerhope.com/unix/rename.htm。]


正确; 诸如CentOS之类的Fedora衍生的OS与renameDebian衍生的OS 具有不同的版本。参见unix.stackexchange.com/a/238862/135943。顺便说一句,CentOS 5.6已经很老了,我建议您升级。
通配符'18

嗯,谢谢您的解释+链接。过时的操作系统正在运行,因此升级不取决于我:),但是正在构建新的群集,迁移时大概会升级...
Ezra Citron

0

这是DTK的解决方案,其中包含可重复使用的bash函数:

function renameFilesRecursively () {

  SEARCH_PATH="$1"
  SEARCH="$2"
  REPLACE="$3"

  find ${SEARCH_PATH} -type f -name "*${SEARCH}*" | while read FILENAME ; do
      NEW_FILENAME="$(echo ${FILENAME} | sed -e "s/${SEARCH}/${REPLACE}/g")";
      mv "${FILENAME}" "${NEW_FILENAME}";
  done

}

使用方法如下:

renameFilesRecursively /home/user/my-files apple orange

0

实际上rename有一个选项完全适合被称为--subst-s简称。无需使用正则表达式语法。

rename -s '#U00a9' 'safe' *

如果要替换/替换多个匹配项,请使用--subst-all-S

顺便说一句,我只是想通过什么(从文件名称中删除)替换字符串...好,我们也有它的选项-d/--delete-D/--delete-all

rename -d '#U00a9' *

-1

另一个选择是使用pyRenamer,这是专门为批量重命名而开发的应用程序。

可以安装 sudo apt-get install pyrenamer

有关用法的详细信息,请参阅GitHub上的README文件


1
如果您真的认为这可以回答问题,请在回答中添加一些说明。就其本身而言,它仅安装一个软件包。您应该解释该命令的作用,并提供一个示例,以处理OP的特定要求。
roaima
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.