使用sed批量重命名文件

时间:2010-03-03 15:52:37

标签: bash shell sed file-rename

目标

更改这些文件名:

  • F00001-0708-RG-biasliuyda
  • F00001-0708-CS-akgdlaul
  • F00001-0708-VF-hioulgigl

这些文件名:

  • F0001-0708-RG-biasliuyda
  • F0001-0708-CS-akgdlaul
  • F0001-0708-VF-hioulgigl

外壳代码

测试:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/'

执行:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' | sh

我的问题

我不明白sed代码。我理解替换是什么 命令

$ sed 's/something/mv'

装置。我有点理解正则表达式。但我没有 了解这里发生了什么:

\(.\).\(.*\)

或在这里:

& \1\2/

前者,对我而言,看起来就像是:“一个角色, 后跟一个字符,后跟任意长度序列 单个字符“ - 但肯定还有更多的东西。至于 后一部分:

& \1\2/

我不知道。我真的很想了解这段代码。请帮我 在这里,伙计们。

13 个答案:

答案 0 :(得分:129)

首先,我应该说最简单的方法是使用 预名或重命名命令。

在Ubuntu,OSX(自制软件包rename,MacPorts软件包p5-file-rename)或其他具有perl重命名(prename)的系统上:

rename s/0000/000/ F0000*

或在从util-linux-ng重命名的系统上,例如RHEL:

rename 0000 000 F0000*

这比同等的sed命令更容易理解。

但是至于理解sed命令,sed联机帮助页很有帮助。如果 你运行man sed并搜索& (使用/命令进行搜索), 你会发现它是s / foo / bar / replacementments中的一个特殊字符。

  s/regexp/replacement/
         Attempt  to match regexp against the pattern space.  If success‐
         ful,  replace  that  portion  matched  with  replacement.    The
         replacement may contain the special character & to refer to that
         portion of the pattern space  which  matched,  and  the  special
         escapes  \1  through  \9  to refer to the corresponding matching
         sub-expressions in the regexp.

因此,\(.\)匹配第一个字符,可由\1引用。 然后.匹配下一个字符,该字符始终为0。 然后\(.*\)匹配文件名的其余部分,可由\2引用。

替换字符串使用&(原始字符串)将它们放在一起 filename)和\1\2,除了第二个文件名,它是文件名的每个部分 字符,这是一个0。

这是一个非常神秘的方式,恕我直言。如果是的话 某些原因,重命名命令不可用,你想使用 sed做重命名(或者你做的事情太复杂了 对于重命名?),在你的正则表达式中更加明确会使它变得更多 更具可读性。也许是这样的事情:

ls F00001-0708-*|sed 's/F0000\(.*\)/mv & F000\1/' | sh

能够看到实际发生了什么变化 s / search / replacement /使其更具可读性。它也不会保留 如果你意外地运行它,就会从你的文件名中吸出字符 两次或者其他什么。

答案 1 :(得分:37)

你已经有了sed解释,现在你可以只使用shell,不需要外部命令

for file in F0000*
do
    echo mv "$file" "${file/#F0000/F000}"
    # ${file/#F0000/F000} means replace the pattern that starts at beginning of string
done

答案 2 :(得分:16)

我写了一篇小文章,其中包含几年前使用sed批量重命名的示例:

http://www.guyrutenberg.com/2009/01/12/batch-renaming-using-sed/

例如:

for i in *; do
  mv "$i" "`echo $i | sed "s/regex/replace_text/"`";
done

如果正则表达式包含组(例如\(subregex\),那么您可以在替换文本中将其用作\1\\2等。

答案 3 :(得分:14)

最简单的方法是:

for i in F00001*; do mv "$i" "${i/F00001/F0001}"; done

或者,便携式,

for i in F00001*; do mv "$i" "F0001${i#F00001}"; done

这会将文件名中的F00001前缀替换为F0001。 在这里得到mahesh:http://www.debian-administration.org/articles/150

答案 4 :(得分:6)

sed命令

s/\(.\).\(.*\)/mv & \1\2/

意味着替换:

\(.\).\(.*\)

使用:

mv & \1\2

就像常规sed命令一样。但是,括号&\n标记会稍微改变它。

搜索字符串匹配(并记忆为模式1)开头的单个字符,后跟单个字符,后跟字符串的其余部分(记为模式2)。

在替换字符串中,您可以参考这些匹配的模式以将其用作替换的一部分。您还可以将整个匹配的部分称为&

那么sed命令正在做什么是基于原始文件(对于源)和字符1和3以及之前创建mv命令,有效地删除字符2(对于目的地)。它将为您提供以下格式的一系列行:

mv F00001-0708-RG-biasliuyda F0001-0708-RG-biasliuyda
mv abcdef acdef

等等。

答案 5 :(得分:2)

反斜杠 - 填充的东西意味着,“在匹配模式的同时,抓住这里匹配的东西。”稍后,在替换文本方面,您可以使用“\ 1”(第一个带括号的块),“\ 2”(第二个块)等来获取那些被记住的片段,依此类推。

答案 6 :(得分:1)

使用perl重命名(工具箱中必须有 ):

rename -n 's/0000/000/' F0000*

当输出看起来不错时,请移除-n开关以重命名为真实。

warning 有些其他具有相同名称的工具可能无法执行此操作,因此请小心。

util-linux软件包中的重命名命令不会。

如果运行以下命令(GNU

$ rename

您会看到perlexpr,这似乎是正确的工具。

如果没有,则将其设置为DebianUbuntu之类的派生类的默认设置(通常已经是这样):

$ sudo apt install rename
$ sudo update-alternatives --set rename /usr/bin/file-rename

对于archlinux:

pacman -S perl-rename

对于RedHat系列发行版:

yum install prename

“ prename”软件包位于EPEL存储库中。


对于Gentoo:

emerge dev-perl/rename

对于* BSD:

pkg install gprename

p5-File-Rename


对于Mac用户:

brew install rename

如果您在另一个发行版中没有此命令,请搜索软件包管理器以进行安装或do it manually

cpan -i File::Rename

可以找到旧的独立版本here


man rename


此工具最初由Perl的父亲Larry Wall编写。

答案 7 :(得分:0)

括号捕获特定字符串以供反斜杠数字使用。

答案 8 :(得分:0)

如果您真正要做的就是删除第二个角色,无论它是什么,您都可以这样做:

s/.//2

但是您的命令正在构建一个mv命令并将其传递给shell以供执行。

这比您的版本更具可读性:

find -type f | sed -n 'h;s/.//4;x;s/^/mv /;G;s/\n/ /g;p' | sh

第四个字符被删除,因为find在每个文件名前加上“./".

答案 9 :(得分:0)

 ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash

答案 10 :(得分:0)

这就是我要做的事情:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done

然后,如果看起来没问题,请将| sh添加到最后。所以:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done | sh

答案 11 :(得分:0)

一些对我有用的例子:

$ tree -L 1 -F .
.
├── A.Show.2020.1400MB.txt
└── Some Show S01E01 the Loreming.txt

0 directories, 2 files

## remove "1400MB" (I: ignore case) ...

$ for f in *; do mv 2>/dev/null -v "$f" "`echo $f | sed -r 's/.[0-9]{1,}mb//I'`"; done;
renamed 'A.Show.2020.1400MB.txt' -> 'A.Show.2020.txt'

## change "S01E01 the" to "S01E01 The"
## \U& : change (here: regex-selected) text to uppercase;
##       note also: no need here for `\1` in that regex expression

$ for f in *; do mv 2>/dev/null "$f" "`echo $f | sed -r "s/([0-9] [a-z])/\U&/"`"; done

$ tree -L 1 -F .
.
├── A.Show.2020.txt
└── Some Show S01E01 The Loreming.txt

0 directories, 2 files
$ 

答案 12 :(得分:-1)

for i in *; do mv $i $(echo $i|sed 's/AAA/BBB/'); done