Reputation: 778
I have a bunch of files that are simply just a unix time. The problem is that their filenames go to millis and the program that scans the directory expects them to be in seconds. So I need to rename all the files to remove the last 3 digits before the .txt extension. IE:
1461758015598.txt --> 1461758015.txt
I am new to regex and bash so I am not sure how to do this.
Upvotes: 3
Views: 1665
Reputation: 95252
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
Upvotes: 3
Reputation: 46846
Mark's answer covers a number of options.
But if you want something recursive, I'd go with a find
based solution like this:
find -E . -regex '.*/[0-9]{13}\.txt' -exec \
sh -c 'set -; mv -v "$0" "${0%???.txt}.txt"' "{}" \;
Notes:
-E
option to tell -regex
to use ERE. If you're using an older OS, you might need to convert the ERE to BRE.${..%..}
instead of ${../../}
, making this POSIX compliant rather than dependent on bash. (It'll work in bash too of course, it just doesn't need to.)find
.If you'd prefer to avoid using find
but still want something recursive in bash, you could use the globstar
option:
shopt -s globstar extglob
for f in **/+([0-9]).txt; do
[[ $f =~ ^[0-9]{13}\.txt$ ]] && mv -v "$f" "${f%...\.txt}.txt"
done
Note that globstar
depends on bash version 4.
Upvotes: 0