Linux rename files as dirname

2019-06-14 17:35发布

问题:

i got lots of files like this:

./1/wwuhw.mp3
./2/nweiewe.mp3
./3/iwqjoiw.mp3
./4/ncionw.MP3
./5/joiwqfm.wmv
./6/jqoifiew.WMV

how can i rename them like this in Linux Bash:

./1/1.mp3
./2/2.mp3
./3/3.mp3
./4/4.MP3
./5/5.wmv
./6/6.WMV

回答1:

Try this,

for i in */*; do mv $i $(dirname $i)/$(dirname $i).${i##*.}; done

For loop iterates over each file in directory one by one. and mv statement renames the each file in directory one by one.



回答2:

Something like this should do the job:

for i in */*; do
    echo mv "${i}" "${i%/*}/${i%/*}.${i##*.}"
done

See e.g. here, what this cryptic parameter expansions (like ${i%/*}) mean in bash.

The script above will only print the commands in the console, without invoking them. Once you are sure you want to proceed, you can remove the echo statement and let it run.



回答3:

If you don't mind using external tool, then rnm can do this pretty easily:

rnm -ns '/pd0/./e/' */*

/pd0/ is the immediate parent directory, /pd1/ is the directory before that and so forth.

-ns means name string and /pd/ and /e/ are name string rules which expands to parent directory and file extension respectively.

The general format of the /pd/ rule is /pd<digit>-<digit>-<delim>/, for example, a rule like /pd0-2-_/ will construct dir0_dir1_dir2 from a directory structure of dir2/dir1/dir0

More examples can be found here.



回答4:

The for loop method, as outlined in some of the other answers, would suffice and work great for most cases where you need to rename every file in a directory to the first parent's directory name. My particular case called for a bit more granularity, where I only wanted to rename a subset of the files in a directory and assert that the operand was, in fact, an actual file, not an empty directory, symbolic link, etc. Using find can achieve exactly what you want in addition to the added ability to apply filtration and processing to the file inputs and outputs.

#####################################
# Same effect as using a `for` loop #
#####################################
#
#   -mindepth 2 : ensures that the file has a parent directory.
#   -type f : ensures that we are working with a `regular file` (not directory, symlink, etc.).

find . -mindepth 2 -type f -exec bash -c 'file="{}"; dir="$(dirname $file)"; mv "$file" "$dir/${dir##*/}.${file##*.}"' \;

#########################
# Additional filtration # 
#########################

# mp3 ONLY (case insensitive) 
find . -mindepth 2 -type f -iname "*.mp3" -exec bash -c 'file="{}"; dir="$(dirname $file)"; mv "$file" "$dir/${dir##*/}.${file##*.}"' \;

# mp3 OR mp4 ONLY (case insensitive)
find . -mindepth 2 -type f \( -iname "*.mp3" -or -iname "*.mp4" \) -exec bash -c 'file="{}"; "dir=$(dirname $file)"; mv "$file" "$dir/${dir##*/}.${file##*.}"' \;