bash script to rename all files in a directory?

2019-04-10 09:13发布

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.

标签: linux bash shell
8条回答
疯言疯语
2楼-- · 2019-04-10 09:48

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, i.e. does not descend into sub-directories

These two scripts solve all of those problems.

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

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

Edit

Fixed problem in previous version that did not properly handle path names.

查看更多
够拽才男人
3楼-- · 2019-04-10 10:01
find . -type f | while read FN; do
  BFN=$(basename "$FN")
  NFN=${BFN%.*}_${BFN}
  echo "$BFN -> $NFN"
  mv "$FN" "$NFN"
done
查看更多
该账号已被封号
4楼-- · 2019-04-10 10:02

For your specific case, you want to use mmv as follows:

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 a.b.txt will be turned into a_a.b.txt, not a.b_a.b.txt.

The mmv program was installed as part of my CygWin but I had to

sudo apt-get install mmv

on my Ubuntu box to get it down. 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. I prefer the terseness of mmv myself but you may not have the option.

查看更多
姐就是有狂的资本
5楼-- · 2019-04-10 10:02
#!/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.

查看更多
Fickle 薄情
6楼-- · 2019-04-10 10:07
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
查看更多
SAY GOODBYE
7楼-- · 2019-04-10 10:08

I like the PERL cookbook's rename script for this. It may not be /bin/sh but you can do regular expression-like renames.

The /bin/sh method would be to use sed/cut/awk to alter each filename inside a for loop. If the directory is large you'd need to rely on xargs.

查看更多
登录 后发表回答