Might be as simple as
cp file.{ext,bak.ext}
bash {} expansion expands to all combinations (unlike [] expantion which lists existing files. So it generates two file names.
The { .... , .... }
provides two options, so you get
file.ext and file.bak.ext
In your script you would use
cp $FILE.{$EXTENTION,bak.$EXTENTION}
And to break up the FILENAME into the two halves you can use
FILE=${FILENAME%.*}
EXTN=${FILENAME##*.}
${VAR%xxxxx} will return the left side of what is in VAR up to the matching pattern, in the case above the pattern is .* so you get everything except the last .*
${VAR##xxxxx} will return the right side of what is in VAR, after the matching pattern. The double hash means get the biggest possible match, in case there is more than one possble match.
To make your script save, check for cases where after obtaining FILE and EXTENTION, that they are not the same thing. This will happen in cases where the file name doesn't have an extention.
A sub-section of your script might look like this:
ls *html | while read FILENAME
do
FILE=${FILENAME%.*}
EXTN=${FILENAME##$FILE}
cp $FILE{$EXTN,.bak$EXTN}
done
This ought to work:
sh <(sed -r 's/^\s*(.*)\s+([0-9\.]+)\s+([0-9A-Z]{8}\.dat)\s*$/mv -iv \3 "\2 \1"/' files)
... where files
is the name of your source file.
What this does is pass the result of the sed
command to a new instance of sh
(the shell), using process substitution. The output of the sed
command is:
mv -iv 000011F4.dat "0.1 New File Name.xlsx"
mv -iv 000011F5.dat "0.2 New File Name.xlsx"
mv -iv 000011F6.dat "0.3 New File Name.xlsx"
mv -iv 000011F7.dat "0.4 New File Name.xlsx"
mv -iv 000011F8.dat "0.5 New File Name.xlsx"
mv -iv 000011F9.dat "0.6 New File Name.xlsx"
Taking the sed
command apart, it searches for a pattern:
^
- the beginning of the line
\s*
- any whitespace at the start
(.*)
- any characters (the parentheses store the result to \1
)
\s+
- at least one whitespace character
([0-9\.]+)
- at least one of 0-9
and .
(stored to \2
)
\s+
- at least one whitespace character
([0-9A-Z]{8}\.dat)
- 8 characters in 0-9
or A-Z
, followed by .dat
(stored to \3
)
\s*
- any whitespace at the end
$
- the end of the line
... and replaces it with mv -iv \3 "\2 \1"
, where \1
to \3
are the previously stored values. You can use something other than a space between the version number and the rest of the filename, if you like.
Here's the result:
$ ls -l
total 60
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F4.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F5.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F6.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F7.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F8.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F9.dat
-rw-rw-r-- 1 z z 222 Aug 8 13:47 files
$ sh <(sed -r 's/^\s*(.*)\s+([0-9\.]+)\s+([0-9A-Z]{8}\.dat)\s*$/mv -iv \3 "\2 \1"/' files)
`000011F4.dat' -> `0.1 New File Name.xlsx'
`000011F5.dat' -> `0.2 New File Name.xlsx'
`000011F6.dat' -> `0.3 New File Name.xlsx'
`000011F7.dat' -> `0.4 New File Name.xlsx'
`000011F8.dat' -> `0.5 New File Name.xlsx'
`000011F9.dat' -> `0.6 New File Name.xlsx'
$ ls -l
total 60
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.1 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.2 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.3 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.4 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.5 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.6 New File Name.xlsx
-rw-rw-r-- 1 z z 222 Aug 8 13:47 files
Best Answer
The answer that you looked at was for a question that did not ask for the actual renaming of files on disk, but just to transform the names of the files as reported on the terminal.
This means that you solution will work if you use the
mv
command instead ofprintf
(which will just print the string to the terminal).I'd still advise you to run the the
printf
loop first to make sure that the names are transformed in the way that you'd expect.It is often safe to just insert
echo
in front of themv
to see what would have been executed (it may be a good idea to do this when you're dealing with loops over potentially destructive command such asmv
,cp
andrm
):or, with nicer formatting: