客观的
更改这些文件名:
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/
我不知道。
首先,我应该说最简单的方法是使用 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/ 中实际发生的变化使其更具可读性。如果您不小心运行了两次或其他什么,它也不会继续从您的文件名中吸取字符。
你已经有了你的 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
几年前,我写了一篇小帖子,其中包含有关使用 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
等。
最简单的方法是:
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
mv "$i" "${i/F00001/F0001}"
。但是+1
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
等等。
ls | sed "s/\(.\).\(.*\)/mv & \1\2/" | bash
ls
、管道通过 sed
和 然后通过 shell 管道是危险的! 它可能会使用伪造的文件名执行任意代码。问题是数据应该被视为数据,在这里它通常被序列化为代码而没有任何预防措施。我希望 paxdiablo 可以删除此答案,因为它确实没有显示出良好的做法。 (我偶然发现了这个问题,因为一个初学者在一个不起作用的命令之后随机传送 | sh
,并且在看到这个问题和答案后认为它会更好地工作 - 我很害怕!) :)
。
使用 perl 重命名(工具箱中必须有):
rename -n 's/0000/000/' F0000*
当输出看起来不错以真正重命名时,删除 -n
开关。
https://i.stack.imgur.com/tWPfj.png
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
如果您在其他发行版中没有此命令,请搜索您的包管理器以安装它或 do it manually:
cpan -i File::Rename
可以找到旧的独立版本 here
这个工具最初是由 Perl 的父亲 Larry Wall 编写的。
反斜杠括号的意思是,“在匹配模式时,保留这里匹配的东西。”稍后,在替换文本方面,您可以使用“\1”(第一个带括号的块)、“\2”(第二个块)等来取回那些记住的片段。
如果您真正要做的只是删除第二个字符,无论它是什么,您都可以这样做:
s/.//2
但是您的命令正在构建一个 mv
命令并将其通过管道传送到 shell 以供执行。
这并不比您的版本更具可读性:
find -type f | sed -n 'h;s/.//4;x;s/^/mv /;G;s/\n/ /g;p' | sh
第四个字符被删除,因为 find
在每个文件名前加上“./”。
| 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
添加到末尾。所以:
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 i in *; do mv $i $(echo $i|sed 's/AAA/BBB/'); done
括号捕获特定字符串以供反斜杠数字使用。
ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash
一些对我有用的例子:
$ 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
$
2>/dev/null 抑制无关输出(警告...)
参考[此线程]:https://stackoverflow.com/a/2372808/1904943
更改案例:https://www.networkworld.com/article/3529409/converting-between-uppercase-and-lowercase-on-the-linux-command-line.html
不定期副业成功案例分享
rename
本身很可能是一个“重命名” 链接。即rename
已从prename
中“重命名”。例如,在 Ubuntu 中:readlink -f $(which rename)
输出/usr/bin/prename
...Davidrename > 完全是一个不同的程序。sh
通过管道传输随机数据是一个很好的建议吗?这是潜在的危险,因为可以执行任意代码(您将数据视为代码)。