【问题标题】:bash script to rename all files in a directory?bash脚本重命名目录中的所有文件?
【发布时间】:2010-12-29 16:39:02
【问题描述】:

我有一堆文件需要重命名。

file1.txt needs to be renamed to file1_file1.txt
file2.avi needs to be renamed to file2_file2.avi

如您所见,我需要 _ 后跟原始文件名。

这些文件很多。

【问题讨论】:

标签: linux bash shell


【解决方案1】:
for file in file*.*
do 
    [ -f "$file" ] && echo mv "$file" "${file%%.*}_$file"
done

递归思路

recurse() {
 for file in "$1"/*;do
    if [ -d "$file" ];then
        recurse "$file"
    else
        # check for relevant files
        # echo mv "$file" "${file%%.*}_$file"
    fi
 done
}
recurse /path/to/files

【讨论】:

  • 我想你的意思是:for file in file*.* ;做 mv "$file" `echo "${file%%.*}_$file"`;完成
  • @Mark,为目录添加测试并不费力。
  • @ghostdog:我同意,shell 扩展处理糟糕文件名的最佳方法,但您建议如何递归地执行此操作 在 bash 2.x/3.x 中?因为你的代码不会遍历子目录。
  • @Siegex。正如我在编辑中说明的那样,您可以纯粹使用 shell 进行递归。它只是一个想法,而不是完整的解决方案,但你明白了。
【解决方案2】:

我喜欢 PERL 食谱的重命名脚本。它可能不是 /bin/sh 但您可以进行类似正则表达式的重命名。

/bin/sh 方法是使用 sed/cut/awk 在 for 循环中更改每个文件名。如果目录很大,则需要依赖 xargs。

【讨论】:

    【解决方案3】:
    #!/bin/bash
    # Don't do this like I did:
    # files=`ls ${1}`
    
    for file in *.*
    do
    if [ -f $file ];
    then
    newname=${file%%.*}_${file}
    mv $file $newname
    fi
    done
    

    这个不会重命名子目录,只会重命名常规文件。

    【讨论】:

    • 从不使用ls的输出进行解析。请参阅mywiki.wooledge.org/ParsingLs 了解原因
    • 如果不解析文件名,其他字段解析ls还是可以的。
    • ${file%%.*} 是什么意思?
    • @benjamin button: "%%" 删除 $file 末尾的模式 ".*"。
    【解决方案4】:
    find . -type f | while read FN; do
      BFN=$(basename "$FN")
      NFN=${BFN%.*}_${BFN}
      echo "$BFN -> $NFN"
      mv "$FN" "$NFN"
    done
    

    【讨论】:

    • 这不处理带有空格或换行符的文件名。也不适用于子目录中的文件,因为它将子目录中的文件移动到顶级目录中。
    【解决方案5】:

    值得一提的是mmv 工具,它是专门为此而设计的。

    这里有描述:http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/mass-rename.html

    ...以及替代品。

    【讨论】:

    • 我认为 askvictor 有点击败你,伙计。
    • 是的,他太着急了,他没有说出主要工具的名字。老实说,我独立地找到了相同的链接来搜索我想到的工具;因为我觉得我的答案更有用,所以我把它搁置了。
    • 你能告诉我哪个平台默认安装了mmv吗?
    • 是的:Rock Linux 包括 mmv;但这并没有多大帮助,因为它是一个相当晦涩的发行版。但是,Red Hat/Fedora/CentOS、Debian/Ubuntu 和 Gentoo 都提供了易于安装的软件包。
    【解决方案6】:

    对于您的具体情况,您希望使用mmv,如下所示:

    pax> ll
    total 0
    drwxr-xr-x+ 2 allachan None 0 Dec 24 09:47 .
    drwxrwxrwx+ 5 allachan None 0 Dec 24 09:39 ..
    -rw-r--r--  1 allachan None 0 Dec 24 09:39 file1.txt
    -rw-r--r--  1 allachan None 0 Dec 24 09:39 file2.avi
    
    pax> mmv '*.*' '#1_#1.#2'
    
    pax> ll
    total 0
    drwxr-xr-x+ 2 allachan None 0 Dec 24 09:47 .
    drwxrwxrwx+ 5 allachan None 0 Dec 24 09:39 ..
    -rw-r--r--  1 allachan None 0 Dec 24 09:39 file1_file1.txt
    -rw-r--r--  1 allachan None 0 Dec 24 09:39 file2_file2.avi
    

    您需要注意通配符匹配不是贪婪的。这意味着文件a.b.txt 将变成a_a.b.txt,而不是a.b_a.b.txt

    mmv 程序是作为 CygWin 的一部分安装的,但我必须这样做

    sudo apt-get install mmv
    

    在我的 Ubuntu 盒子上把它弄下来。如果它不在您的标准发行版中,那么您使用的任何包管理器都有望提供它。

    如果由于某种原因不允许您安装它,则必须使用其他答案中显示的其他 bash for-loop-type 解决方案之一。我自己更喜欢 mmv 的简洁性,但你可能没有选择。

    【讨论】:

      【解决方案7】:

      我使用 prename(基于 perl),它包含在各种 linux 发行版中。它适用于正则表达式,所以说将所有 img_x.jpg 更改为 IMAGE_x.jpg 你会这样做

      prename 's/img_/IMAGE_/' img*jpg
      

      您可以使用 -n 标志来预览更改,而无需进行任何实际更改。

      prename man entry

      【讨论】:

        【解决方案8】:

        到目前为止,所有答案都给出了:

        1. 需要一些非便携式工具
        2. 用包含空格或换行符的文件名来破坏
        3. 不递归,即不下降到子目录

        这两个脚本解决了所有这些问题。

        重击 2.X/3.X

        #!/bin/bash
        
        while IFS= read -r -d $'\0' file; do
            dirname="${file%/*}/"
            basename="${file:${#dirname}}"
            echo mv "$file" "$dirname${basename%.*}_$basename"
        done < <(find . -type f -print0)
        

        重击 4.X

        #!/bin/bash
        
        shopt -s globstar
        for file in ./**; do 
            if [[ -f "$file" ]]; then
                dirname="${file%/*}/"
                basename="${file:${#dirname}}"
                echo mv "$file" "$dirname${basename%.*}_$basename"
            fi
        done
        

        一旦您对它的输出感到满意,请务必从您选择的任何脚本中删除 echo,然后再次运行它

        编辑

        修复了以前版本中没有正确处理路径名的问题。

        【讨论】:

        • 我测试了您的 bash2.x/3.x 解决方案。我的输出示例——> mv ./file2.txt _./file2.txt
        • 使用 shell 扩展仍然是最好的方法,即使是文件名中的换行符
        • @levislevis85:修复了路径名的问题,但它确实适用于换行符,只是 echo 让你不这么认为。
        • 很高兴你想出了一个解决方案来完成所有这些事情......但请注意,这个问题是专门针对 Linux 上 1 个目录中的文件提出的,文件名没有什么异常。
        • @Code Duck:添加递归功能是一项微不足道的任务,应该永远假设任何关于文件名的内容,总是将它们视为包含换行符或其他讨厌的东西。第二个你不知道的是当有人添加一个可怕地破坏你的脚本并且天知道是什么的时候。
        猜你喜欢
        • 2015-08-02
        • 2020-07-16
        • 2021-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-27
        • 2017-09-15
        • 1970-01-01
        相关资源
        最近更新 更多