简体   繁体   English

bash脚本重命名目录中的所有文件?

[英]bash script to rename all files in a directory?

i have bunch of files that needs to be renamed. 我有一堆需要重命名的文件。

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

as you can see i need the _ folowed by the original file name. 你可以看到我需要_原始文件名。

there are lot of these files. 这些文件很多。

So far all the answers given either: 到目前为止,所有答案都给出了:

  1. Require some non-portable tool 需要一些非便携式工具
  2. Break horribly with filenames containing spaces or newlines 使用包含空格或换行符的文件名可怕地破坏
  3. Is not recursive, ie does not descend into sub-directories 不是递归的,即不会下降到子目录中

These two scripts solve all of those problems. 这两个脚本解决了所有这些问题。

Bash 2.X/3.X Bash 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)

Bash 4.X Bash 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

Be sure to remove the echo from whichever script you choose once you are satisfied with it's output and run it again 一旦您对其输出感到满意并再次运行,请确保从您选择的任何脚本中删除echo

Edit 编辑

Fixed problem in previous version that did not properly handle path names. 修复了以前版本中未正确处理路径名的问题。

for file in file*.*
do 
    [ -f "$file" ] && echo mv "$file" "${file%%.*}_$file"
done

Idea for recursion 递归的想法

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 your specific case, you want to use mmv as follows: 对于您的具体情况,您希望使用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

You need to be aware that the wildcard matching is not greedy. 您需要知道通配符匹配并不贪婪。 That means that the file abtxt will be turned into a_a.b.txt , not a.b_a.b.txt . 这意味着文件abtxt将变为a_a.b.txt ,而不是a.b_a.b.txt

The mmv program was installed as part of my CygWin but I had to mmv程序是作为我的CygWin的一部分安装的,但我必须这样做

sudo apt-get install mmv

on my Ubuntu box to get it down. 在我的Ubuntu盒子上让它失望。 If it's not in you standard distribution, whatever package manager you're using will hopefully have it available. 如果它不在您的标准发行版中,那么您使用的任何包管理器都希望它可用。

If, for some reason, you're not permitted to install it, you'll have to use one of the other bash for -loop-type solutions shown in the other answers. 如果出于某种原因,您不允许安装它,则必须使用其他答案中显示的其他bash for -loop类型解决方案之一。 I prefer the terseness of mmv myself but you may not have the option. 我更喜欢mmv的mmv但你可能没有选择。

find . -type f | while read FN; do
  BFN=$(basename "$FN")
  NFN=${BFN%.*}_${BFN}
  echo "$BFN -> $NFN"
  mv "$FN" "$NFN"
done

I like the PERL cookbook's rename script for this. 我喜欢PERL cookbook的重命名脚本。 It may not be /bin/sh but you can do regular expression-like renames. 它可能不是/ bin / sh,但您可以进行正则表达式重命名。

The /bin/sh method would be to use sed/cut/awk to alter each filename inside a for loop. / bin / sh方法是使用sed / cut / awk来改变for循环中的每个文件名。 If the directory is large you'd need to rely on xargs. 如果目录很大,则需要依赖xargs。

One should mention the mmv tool, which is especially made for this. 应该提到mmv工具,这是专门为此而设计的。

It's described here: http://tldp.org/LDP/GNU-Linux-Tools-Summary/html/mass-rename.html 它在这里描述: http//tldp.org/LDP/GNU-Linux-Tools-Summary/html/mass-rename.html

...along with alternatives. ......以及其他选择。

I use prename (perl based), which is included in various linux distributions. 我使用prename(基于perl),它包含在各种Linux发行版中。 It works with regular expressions, so to say change all img_x.jpg to IMAGE_x.jpg you'd do 它适用于正则表达式,所以要将所有img_x.jpg更改为你要做的IMAGE_x.jpg

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

You can use the -n flag to preview changes without making any actual changes. 您可以使用-n标志预览更改,而不进行任何实际更改。

prename man entry prename man entry

#!/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

This one won't rename sub directories, only regular files. 这个不会重命名子目录,只重命名常规文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM