104

客观的

更改这些文件名:

  • 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/

我不知道。

4

13 回答 13

170

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

在 Ubuntu、OSX(Homebrew 包rename、MacPorts 包p5-file-rename)或其他带有 perl 重命名(前名)的系统上:

rename s/0000/000/ F0000*

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

rename 0000 000 F0000*

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

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

  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

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

恕我直言,这是一种非常神秘的方法。如果由于某种原因重命名命令不可用,并且您想使用 sed 进行重命名(或者您正在做一些过于复杂而无法重命名的事情?),那么在您的正则表达式中更加明确会使其更具可读性。也许是这样的:

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

能够看到 s/search/replacement/ 中实际发生的变化使其更具可读性。如果您不小心运行了两次或其他什么,它也不会继续从您的文件名中吸取字符。

于 2010-03-03T15:55:16.333 回答
53

你已经有了你的 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
于 2010-03-03T16:02:40.933 回答
37

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

于 2013-06-22T18:40:28.147 回答
25

最简单的方法是:

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

于 2013-09-01T11:02:15.987 回答
8

sed命令_

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

替换的意思:

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

和:

mv & \1\2

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

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

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

因此,该sed命令所做的是mv基于原始文件(对于源文件)和字符 1 和 3 开始创建命令,从而有效地删除字符 2(对于目标文件)。它将按照以下格式为您提供一系列行:

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

等等。

于 2010-03-03T16:05:33.673 回答
4

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

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

-n当输出看起来不错以真正重命名时删除开关。

警告 还有其他同名的工具可能会也可能不会这样做,所以要小心。

作为包的一部分的重命名命令util-linux不会。

如果您运行以下命令 ( GNU)

$ rename

你看perlexpr,那么这似乎是正确的工具。

如果不是,则使其成为默认值(通常已经如此)Debian和衍生,例如Ubuntu

$ 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

如果您在其他发行版中没有此命令,请搜索您的包管理器以安装它或手动执行

cpan -i File::Rename

旧的独立版本可以在这里找到


人重命名


这个工具最初是由 Perl 的父亲 Larry Wall 编写的。

于 2020-06-29T14:04:34.723 回答
3

反斜杠括号的意思是,“在匹配模式时,保留这里匹配的东西。” 稍后,在替换文本方面,您可以使用“\1”(第一个带括号的块)、“\2”(第二个块)等来取回那些记住的片段。

于 2010-03-03T15:54:57.147 回答
1

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

s/.//2

但是您的命令正在构建一个mv命令并将其通过管道传输到外壳程序以执行。

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

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

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

于 2010-03-03T17:12:37.677 回答
1

这是我要做的:

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
于 2013-08-27T22:59:43.660 回答
1
for i in *; do mv $i $(echo $i|sed 's/AAA/BBB/'); done
于 2020-04-30T03:05:03.050 回答
0

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

于 2010-03-03T15:55:34.103 回答
0
 ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash
于 2010-03-04T07:13:51.473 回答
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
$ 
于 2020-12-11T19:11:24.503 回答