Reputation:
I am trying to rename a batch of files of the form:
test1_run1
test1_run2
...
test1_run10
...
test10_run1
test10_run2
...
test10_run10
to the form with multiple paddings. For the first number I need padding with zeros of length 5 and for the second with length 3.
The final result should be of the form:
test00001_run001
test00001_run002
...
test00001_run010
...
test00010_run001
test00010_run002
...
test00010_run010
How can I do this in bash for all the files in a particular folder?
Upvotes: 0
Views: 213
Reputation: 46823
In bash:
#!/bin/bash
shopt -s nullglob extglob
for file in test+([[:digit:]])_run+([[:digit:]]); do
[[ $file =~ ^test([[:digit:]]+)_run([[:digit:]]+)$ ]]
printf -v newfile 'test_%05d_run%03d' "$((10#${BASH_REMATCH[1]}))" "$((10#${BASH_REMATCH[2]}))"
echo mv "$file" "$newfile"
done
Run this from within the folder you want to process. This will only echo
the mv
commands to be performed. Remove the echo
if you're happy with the result.
nullglob
so that non-matching globs expand to nothing;extglob
because the for
loop will use extended globs;test+([[:digit:]])_run+([[:digit:]])
will expand to the files matching this pattern (if any)BASH_REMATCH[1]
and the second in BASH_REMATCH[2]
.printf
to format the new file name; the modifiers %05d
and %03d
will format the numbers according to your wishes (with appropriate leading zeroes). Observe that we're using ((10#${BASH_REMATCH[1]}))
to explicitly specify that the number is in radix 10, in case you have a file test09_run001
. The 09
part would make bash misinterpret the number in radix 8 (because of the leading 0) and you'll get a complaint; the -v
switch tells printf
to not output on standard output, but to store the output in variable newfile
;mv
.Upvotes: 1
Reputation: 29021
If you don't want to use perl or awk, and strictly use bash and some utility programs that are available in most distribution, you can try something like this:
for i in * ; do
testpart=`echo $i | cut -d_ -f1`
testnum=${testpart#test}
runpart=`echo $i | cut -d_ -f2`
runnum=${runpart#run}
destfile=test`printf %05d $testnum`_run`printf %03d $runnum`
mv $i $destfile
done
Upvotes: 1
Reputation: 289605
We can convert the string into test
+ 5 digits
+ _run
+ 3 digits
formats by saying:
$ awk -F"test" '{split($2,a,"_run"); printf "%s%0.5d%s%0.3d\n", FS, a[1], "_run", a[2]}' a
test00001_run001
test00001_run002
test00001_run010
test00010_run001
test00010_run002
test00010_run010
This works by using test
as field separator and splitting the 2nd field in two parts: before and after _run
. Then, it uses the printf
thingies to get the proper output.
Then, you can print mv
together with the previous value and say:
$ awk -F"test" '{split($2,a,"_run"); printf "mv %s %s%0.5d%s%0.3d\n", $0, FS, a[1], "_run", a[2]}' a
mv test1_run1 test00001_run001
mv test1_run2 test00001_run002
mv test1_run10 test00001_run010
mv test10_run1 test00010_run001
mv test10_run2 test00010_run002
mv test10_run10 test00010_run010
If you then pipe it to sh
, it will get executed.
Upvotes: 1