Rename a file to swap extensions in Unix - bash

I have a bunch of files which are copied by "mv --backup=t source destination". So these files are in format *.*.~[0-9]~
For example,
some_file_name.pdf.~1~
some_file_name.pdf.~2~
another_file_name.docx.~1~
another_file_name.docx.~2~
Now, I would like to rename all such files so that the backup extension number came before the actual extension. Like
some_file_name_1.pdf
some_file_name_2.pdf
another_file_name_1.docx
another_file_name_2.docx
Is there a way to do in Unix using shell?
Any thoughts would be appreciated. Thank you in advance.

Using BASH regex directives you can do this:
for f in *~; do
[[ $f =~ ^(.+)\.([^.]+)\.~([0-9]+)~$ ]] &&
echo mv "$f" "${BASH_REMATCH[1]}_${BASH_REMATCH[3]}.${BASH_REMATCH[2]}"
done
Output:
mv CR_71050_5.3.17.pdf.~1~ CR_71050_5.3.17_1.pdf
mv another_file_name.docx.~1~ another_file_name_1.docx
mv another_file_name.docx.~2~ another_file_name_2.docx
mv some_file_name.pdf.~1~ some_file_name_1.pdf
mv some_file_name.pdf.~2~ some_file_name_2.pdf
Once you're satisfied, you can remove echo before mv

Try:
awk -F~ '{ split($1,splt,".");system("mv "$0" "splt[1]"_"$2"."splt[2]) }'
We are essentially splitting the filenames on ~ and then using awks split function to further split the text and then pass it to the system function to execute the mv command.

You can use rename (it is available as a Debian package).
$ ls
file.pdf.~1~ file.pdf.~10~ file.pdf.~2~ file.pdf.~3~ file.pdf.~9~
$ rename 's/.pdf.~([0-9]+)~$/$1.pdf/' *.pdf.~*~
$ ls
file10.pdf file1.pdf file2.pdf file3.pdf file9.pdf

Related

remove strange char and adding a prefix when renaming on ssh

i have found this command to replace spaces with underscores:
for file in *.jpg; do mv "$file" ${file// /_}; done
but many pics have chars like ' # ñ and want to remove those automatically and also wanted to add a suffix o prefix.
ex.
pic's#nick_0001.jpg
pic's#nick_0003.jpg
pic's#nick_0003.jpg
to
vacations_pics_nick_0001.jpg
pics_nick_0001_vacations.jpg
can you help me?
for file in *.jpg
do
mv "$file" $(sed 's/[^ [:alnum:]]//g;s/ /_/g;s/^/your_prefix/' <<<"$file")
done
Should do the job
both solution works fine.
is there a way to use that command on a single line, like the example i give to use with others comand together:
for file in * do mv "$file" "${file//[^a-z0-9]/_}" done;
??'
Using bash:
for file in *
do
mv "$file" "${file//[^a-z0-9]/_}"
done
Test:
$ touch "pic's#nick_0001.jpg"
$ ls
pic's#nick_0001.jpg
$ for file in *; do mv "$file" "${file//[^a-z0-9]/_}"; done
$ ls
pic_s_nick_0001_jpg

remove substring from filename

I have files with name of the form "NAME-xxxxxx.tedx" and I want to remove the "-xxxxxx" part. The x are all digits.
The regex "\-[0-9]{1,6}" matches the substring, but I have no idea how to remove it from the filename.
Any idea how I can do that in the shell?
If you have the perl version of the rename command installed, you could try:
rename 's/-[0-9]+//' *.tedx
Demo:
[me#home]$ ls
hello-123.tedx world-23456.tedx
[me#home]$ rename 's/-[0-9]+//' *.tedx
[me#home]$ ls
hello.tedx world.tedx
This command is smart enough to not rename files if it means overwriting an existing file:
[me#home]$ ls
hello-123.tedx world-123.tedx world-23456.tedx
[me#home]$ rename 's/-[0-9]+//' *.tedx
world-23456.tedx not renamed: world.tedx already exists
[me#home]$ ls
hello.tedx world-23456.tedx world.tedx
echo NAME-12345.tedx | sed "s/-[0-9]*//g"
will give NAME.tedx. So you can use a loop and move the files using mv command:
for file in *.tedx; do
newfile=$(echo "$file" | sed "s/-[0-9]*//g")
mv "$file" $newfile
done
If you want to use just the shell
shopt -s extglob
for f in *-+([0-9]]).tedx; do
newname=${f%-*}.tedx # strip off the dash and all following chars
[[ -f $newname ]] || mv "$f" "$newname"
done

Rename all files in directory from $filename_h to $filename_half?

Dead simple.
How do I rename
05_h.png
06_h.png
to
05_half.png
06_half.png
At least, I think it's simple, but it's hard to Google for this kind of thing unless you already know.
Thanks....
Just use bash, no need to call external commands.
for file in *_h.png
do
mv "$file" "${file/_h.png/_half.png}"
done
Do not add #!/bin/sh
For those that need that one-liner:
for file in *.png; do mv "$file" "${file/_h.png/_half.png}"; done
Try rename command:
rename 's/_h.png/_half.png/' *.png
Update:
example usage:
create some content
$ mkdir /tmp/foo
$ cd /tmp/foo
$ touch one_h.png two_h.png three_h.png
$ ls
one_h.png three_h.png two_h.png
test solution:
$ rename 's/_h.png/_half.png/' *.png
$ ls
one_half.png three_half.png two_half.png
for f in *.png; do
fnew=`echo $f | sed 's/_h.png/_half.png/'`
mv $f $fnew
done
Or in one-liner:
for f in *.png; do mv "$f" "$(echo $f | sed 's/_h.png$/_half.png/g')"; done
Are you looking for a pure bash solution? There are many approaches, but here's one.
for file in *_h.png ; do mv "$file" "${file%%_h.png}_half.png" ; done
This presumes that the only files in the current directory that end in _h.png are the ones you want to rename.
Much more specifically
for file in 0{5..6}_h.png ; do mv "$file" "${file/_h./_half.}" ; done
Presuming those two examples are your only. files.
For the general case, file renaming in has
been covered
before.
Use the rename utility written in perl.
Might be that it is not available by default though...
$ touch 0{5..6}_h.png
$ ls
05_h.png 06_h.png
$ rename 's/h/half/' *.png
$ ls
05_half.png 06_half.png
for i in *_h.png ; do
mv $i `echo "$i"|awk -F'.' '{print $1"alf."$2}'`
done
I had a similar question:
In the manual, it describes rename as
rename [option] expression replacement file
so you can use it in this way
rename _h _half *.png
In the code:
'_h' is the expression that you are looking for.
'_half' is the pattern that you want to replace with.
'*.png' is the range of files that you are looking for your possible target files.
Hope this can help c:
Another approach can be manually using batch rename option
Right click on the file -> File Custom Commands -> Batch Rename
and you can replace h. with half.
This will work for linux based gui using WinSCP etc
One liner:
for file in *.php ; do mv "$file" "_$file" ; done
Although the answer set is complete, I need to add another missing one.
for i in *_h.png;
do name=`echo "$i" | cut -d'_' -f1`
echo "Executing of name $name"
mv "$i" "${name}_half.png"
done
I had to rename the prefix of files and I found this answer with a solution like this:
for i in h_*; do mv ${i/#h_/half_}; done
If pattern begins with #, it must match at the beginning of the
expanded value of parameter. If pattern begins with %, it must match
at the end of the expanded value of parameter.
from man bash
Use the rename utility:
rc#bvm3:/tmp/foo $ touch 05_h.png 06_h.png
rc#bvm3:/tmp/foo $ rename 's/_h/_half/' *
rc#bvm3:/tmp/foo $ ls -l
total 0
-rw-r--r-- 1 rc rc 0 2011-09-17 00:15 05_half.png
-rw-r--r-- 1 rc rc 0 2011-09-17 00:15 06_half.png

batch rename files with ids intact

i have a directory listing like
seascaperecovered0088crop.jpg
seascaperecovered0096crop.jpg
seascaperecovered0098crop.jpg
seascaperecovered0101crop.jpg
seascaperecovered0103crop.jpg
seascaperecovered0105crop.jpg
seascaperecovered0107crop.jpg
seascaperecovered0112crop.jpg
seascaperecovered0119crop.jpg
seascaperecovered0122crop.jpg
and i want to rename all files as seen here:
seascape_0122.jpg
i have tried something like this:
for f in `ls | egrep 'seascaperecovered.*\.jpg'`;
do mv $f ${f/seascaperecovered/seascape};
done
i have read that you can do this with mv, rename, sed, awk, etc.
can someone point me to the easiest (and clearest, hopefully) way of accomplishing this in UNIX?
FWIW, I am ssh'd into a Linux machine and running a bash shell.
thanks,
jml
Very straightforward:
for i in seascaperecovered*.jpg; do A=${i/crop/}; mv $i ${A/recovered/_}; done
(Put echo before the mv first for a dry run.)
With bash regular expressions
for file in *; do
[[ "$file" =~ [0-9]+ ]] && mv "$file" seascape_${BASH_REMATCH[0]}.jpg
done

How to replace backslashes from windows formatted files into *nix format and reestablish structure

I have a fair few files that have been extracted from a zip created in a strange way.
the files have come out of the tar.gz in windows file structure format
Example:
jpg_250\MI\00\00\00\19\MI0000001900.jpg
versus
jpg_250/MI/00/00/00/19/MI0000001900.jpg
The former is seen as a single file by linux.
I've been playing around with awk and sed to delimit the filename by backslash, and create the directories in question in the correct structure, and finally rename the file to the MI**.jpg and move it into the correct newly created end directory.
Is awk and sed the way to go here? I have awk exploding the filename into the 'directories' I need but I'm having trouble getting the directories actually created. I assume I would need sed at the end to rename the file into the MI**.jpg format.
Many thanks for any help.
Something like this?
$ ls
a\b\c
a\b\d
$ for i in *; do
F=$(echo $i | sed 's,\\,/,g')
D=$(dirname $F)
echo mkdir -p ${D}
echo cp "${i}" "${F}"
done
mkdir -p a/b
cp a\b\c a/b/c
mkdir -p a/b
cp a\b\d a/b/d
You could do this with Perl like this.
# assume that the script was called like this:
# myscript file1 file2 etc...
# then all the files are in #ARGV
foreach $orig (#ARGV) {
$orig_fixed = $orig;
# convert the \ to /
$orig_fixed =~ s!\\!/!g;
#split the filename into directory and filename
($dir, $filename) = ($orig_fixed =~ m!^(.*)/([^/]*)$!);
# create the directory if it doesn't exist
if (!-e $dir) {
`mkdir -p $dir`; # -p means create the full path
}
# now move the file
`mv '$orig' $dir/$filename`;
}

Resources