bash 使用 sed 批量重命名文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2372719/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 18:59:43  来源:igfitidea点击:

Using sed to mass rename files

bashshellsedfile-rename

提问by Daniel Underwood

Objective

客观的

Change these filenames:

更改这些文件名:

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

to these filenames:

到这些文件名:

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

Shell Code

外壳代码

To test:

去测试:

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

To perform:

去表演:

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

My Question

我的问题

I don't understand the sed code. I understand what the substitution command

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

$ sed 's/something/mv'

means. And I understand regular expressions somewhat. But I don't understand what's happening here:

方法。而且我对正则表达式有些了解。但我不明白这里发生了什么:

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

or here:

或在这里:

& /

The former, to me, just looks like it means: "a single character, followed by a single character, followed by any length sequence of a single character"--but surely there's more to it than that. As far as the latter part:

对我来说,前者看起来就像是:“一个字符,然后是单个字符,然后是单个字符的任意长度序列”——但肯定不止于此。至于后半部分:

& /

I have no idea.

我不知道。

回答by Edward Anderson

First, I should say that the easiest way to do this is to use the prename or rename commands.

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

On Ubuntu, OSX (Homebrew package rename, MacPorts package p5-file-rename), or other systems with perl rename (prename):

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

rename s/0000/000/ F0000*

or on systems with rename from util-linux-ng, such as RHEL:

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

rename 0000 000 F0000*

That's a lot more understandable than the equivalent sed command.

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

But as for understanding the sed command, the sed manpage is helpful. If you run man sed and search for & (using the / command to search), you'll find it's a special character in s/foo/bar/ replacements.

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

  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    through    to refer to the corresponding matching
         sub-expressions in the regexp.

Therefore, \(.\)matches the first character, which can be referenced by \1. Then .matches the next character, which is always 0. Then \(.*\)matches the rest of the filename, which can be referenced by \2.

因此,\(.\)匹配第一个字符,可以通过\1. 然后.匹配下一个字符,它总是 0。然后\(.*\)匹配文件名的其余部分,可以通过\2.

The replacement string puts it all together using &(the original filename) and \1\2which is every part of the filename except the 2nd character, which was a 0.

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

This is a pretty cryptic way to do this, IMHO. If for some reason the rename command was not available and you wanted to use sed to do the rename (or perhaps you were doing something too complex for rename?), being more explicit in your regex would make it much more readable. Perhaps something like:

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

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

Being able to see what's actually changing in the s/search/replacement/ makes it much more readable. Also it won't keep sucking characters out of your filename if you accidentally run it twice or something.

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

回答by ghostdog74

you've had your sed explanation, now you can use just the shell, no need external commands

你已经有了你的 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

回答by Guy

I wrote a small post with examples on batch renaming using sedcouple of years ago:

sed几年前,我写了一篇关于批量重命名示例的小文章:

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

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

For example:

例如:

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

If the regex contains groups (e.g. \(subregex\) then you can use them in the replacement text as \1\,\2etc.

如果正则表达式中包含组(如\(subregex\),那么你可以在替换文本使用它们\1\\2等等。

回答by Mike

The easiest way would be:

最简单的方法是:

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

or, portably,

或者,便携地,

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

This replaces the F00001prefix in the filenames with F0001. credits to mahesh here: http://www.debian-administration.org/articles/150

这会将F00001文件名中的前缀替换为F0001. 此处归功于 mahesh:http: //www.debian-administration.org/articles/150

回答by paxdiablo

The sedcommand

sed命令

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

means to replace:

替换的意思:

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

with:

和:

mv & 

just like a regular sedcommand. However, the parentheses, &and \nmarkers change it a little.

就像一个普通的sed命令。但是,括号&\n标记对其进行了一些更改。

The search string matches (and remembers as pattern 1) the single character at the start, followed by a single character, follwed by the rest of the string (remembered as pattern 2).

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

In the replacement string, you can refer to these matched patterns to use them as part of the replacement. You can also refer to the whole matched portion as &.

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

So what that sedcommand is doing is creating a mvcommand based on the original file (for the source) and character 1 and 3 onwards, effectively removing character 2 (for the destination). It will give you a series of lines along the following format:

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

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

and so on.

等等。

回答by Pointy

The backslash-paren stuff means, "while matching the pattern, hold on to the stuff that matches in here." Later, on the replacement text side, you can get those remembered fragments back with "\1" (first parenthesized block), "\2" (second block), and so on.

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

回答by Paused until further notice.

If all you're really doing is removing the second character, regardless of what it is, you can do this:

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

s/.//2

but your command is building a mvcommand and piping it to the shell for execution.

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

This is no more readable than your version:

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

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

The fourth character is removed because findis prepending each filename with "./".

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

回答by ghostdog74

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

回答by Ewan Todd

The parentheses capture particular strings for use by the backslashed numbers.

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

回答by Chris Po

Here's what I would do:

这是我会做的:

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

Then if that looks ok, add | shto the end. So:

然后如果看起来没问题,添加| 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