If the files are always one directory level deep, then you can iterate over them with something like for x in */*_20*_*
. Which pattern to use depends on what other files might be present that you don't want to rename. The pattern I just gave assumes that the date starts with 20
and that all files whose name contains _20
and another undescore after that should be renamed.
You can do the renaming with a shell loop, using parameter expansion constructs to build the new file name.
for old_name in ./*/*_20_*_*; do
base=${old_name##*/} # remove the directory part
prefix=${base%%_20*} # remove everything from _20
suffix=${base#*_20} # remove everything up to _20
suffix=${suffix#*_} # ... then everything before the first remaining _
mv "$old_name" "${old_name%/*}/${prefix}_${suffix}"
done
If the files are at varying depths, in bash ≥4.3, you can run shopt -s globstar
then for x in **/*_20*_*; …
. The pattern **
matches any directory depth if globstar
is turned on. This also works in bash 4.0–4.2 with the caveat that it also traverses symbolic links to directories. This also works in zsh and ksh, without the caveat, out of the box in zsh and with set -o globstar
in ksh.
rename
command is the perl rename only on Debian and derivatives. – Gilles 'SO- stop being evil' May 27 '17 at 22:42