Here's one way:
for f in *.txt; do
mv "$f" "${f/[0-9][0-9][0-9].txt/.txt}"
done
Between the do
and done
, it's looking at one file at a time, and the current file's name is in the paramter f
. "$f"
is the value of that parameter, unchanged. "${f/[0-9][0-9][0-9].txt/.txt}"
is the value of the parameter with a substitution applied: replace "three digits followed by .txt
" with just .txt
.
As @anubhava pointed out, if you run it more than once it will keep lopping digits off the filenames, so don't do that. You can make it idempotent by tightening up the glob pattern. This is a little unwieldy:
for f in [0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9].txt; do
mv "$f" "${f/[0-9][0-9][0-9].txt/.txt}"
done
So you might want to use an external tool to make it more compact (this assumes there are no spaces or newlines in any filenames in the directory):
for f in $(ls -1 | egrep '^[0-9]{13}\.txt$'); do
mv "$f" "${f/[0-9][0-9][0-9].txt/.txt}"
done
You can reduce the restriction to just "no newlines" by using a while read
loop:
ls -1 | egrep '^[0-9]{13}\.txt$' | while read f; do
mv "$f" "${f/[0-9][0-9][0-9].txt/.txt}"
done