batch rename files in ubuntu - linux

I am in need of some command line fu.
I have a wack of files, starting with 4 numbers then a dash then various letters then extentsion, eg.
0851_blahblah_p.dbf
0754_asdf_l.dbf
What I want is to move the four numbers to the end of the filename (keeping the extension in tact) and remove the underscore. Thus the above example would be renamed:
blahblah_p0851.dbf
asdf_l0754.dbf
All help is appreciated.
I am running ubuntu.
Thanks DJ

Here is a solution in pure bash:
for file in *.dbf; do
ext=${file##*.};num=${file%%_*};name=${file%.*};name=${name#*_}
mv $file $name$num"."$ext;
done
Broken down with comments:
for file in *.dbf
do
ext=${file##*.} # Capture the extension
num=${file%%_*} # Capture the number
name=${file%.*} # Step 1: Capture the name
name=${name#*_} # Step 2: Capture the name
mv "$file" "$name$num.$ext" # move the files to new name
done

You can use the rename command:
rename 's/([0-9]{4})_([[:alpha:]]*)_.*.dbf/$2_$1.dbf/' *

You can use sed also
$sed -r 's/([^_]+)_([^.]+)/\2\1/g'
Using this way the given name is splitted and modified as per your requirement.
(or)
Use this script and pass the file names as argument it will move the file name as per the requirement.
#!/bin/sh
if [ $# -ne 1 ] ; then
echo "Usage : <sh filename> <arguments>"
exit ;
fi
for file in $*
do
mv $file `echo $file | sed -r 's/([^_]+)_([^.]+)/\2\1/g' `
done

Related

Modify file name using Python Script

I have many files in my folder with names 1.jpg-xyz, 1.jpg-abc, 2.jpg-qwe etc. I particularly want to move .jpg to the end of each image's name. I can't do it manually since these are thousands in number. I can't get rid of xyz etc after .jpg in the current name since they have important information. So only option I have is to shift .jpg to end. Can somebody tell me what command or script should I use to do that?
This should work:
find *jpg* | while read f ; do g=$(echo "$f" | sed s/\.jpg//) ; echo "mv $f ${g}.jpg" ; done
If the mv commands echoed look like what you want then remove the echo "" around it and re-run.
The below bash code will list all files with .jpg- and move them to -.jpg
re='([^.]+)\.jpg(-.*)'
for file in *.jpg-*
do
if [[ $file =~ $re ]]
then
mv $file "${BASH_REMATCH[1]}${BASH_REMATCH[2]}.jpg"
fi
done

How to remove the extension of a file?

I have a folder that is full of .bak files and some other files also. I need to remove the extension of all .bak files in that folder. How do I make a command which will accept a folder name and then remove the extension of all .bak files in that folder ?
Thanks.
To remove a string from the end of a BASH variable, use the ${var%ending} syntax. It's one of a number of string manipulations available to you in BASH.
Use it like this:
# Run in the same directory as the files
for FILENAME in *.bak; do mv "$FILENAME" "${FILENAME%.bak}"; done
That works nicely as a one-liner, but you could also wrap it as a script to work in an arbitrary directory:
# If we're passed a parameter, cd into that directory. Otherwise, do nothing.
if [ -n "$1" ]; then
cd "$1"
fi
for FILENAME in *.bak; do mv "$FILENAME" "${FILENAME%.bak}"; done
Note that while quoting your variables is almost always a good practice, the for FILENAME in *.bak is still dangerous if any of your filenames might contain spaces. Read David W.'s answer for a more-robust solution, and this document for alternative solutions.
There are several ways to remove file suffixes:
In BASH and Kornshell, you can use the environment variable filtering. Search for ${parameter%word} in the BASH manpage for complete information. Basically, # is a left filter and % is a right filter. You can remember this because # is to the left of %.
If you use a double filter (i.e. ## or %%, you are trying to filter on the biggest match. If you have a single filter (i.e. # or %, you are trying to filter on the smallest match.
What matches is filtered out and you get the rest of the string:
file="this/is/my/file/name.txt"
echo ${file#*/} #Matches is "this/` and will print out "is/my/file/name.txt"
echo ${file##*/} #Matches "this/is/my/file/" and will print out "name.txt"
echo ${file%/*} #Matches "/name.txt" and will print out "/this/is/my/file"
echo ${file%%/*} #Matches "/is/my/file/name.txt" and will print out "this"
Notice this is a glob match and not a regular expression match!. If you want to remove a file suffix:
file_sans_ext=${file%.*}
The .* will match on the period and all characters after it. Since it is a single %, it will match on the smallest glob on the right side of the string. If the filter can't match anything, it the same as your original string.
You can verify a file suffix with something like this:
if [ "${file}" != "${file%.bak}" ]
then
echo "$file is a type '.bak' file"
else
echo "$file is not a type '.bak' file"
fi
Or you could do this:
file_suffix=$(file##*.}
echo "My file is a file '.$file_suffix'"
Note that this will remove the period of the file extension.
Next, we will loop:
find . -name "*.bak" -print0 | while read -d $'\0' file
do
echo "mv '$file' '${file%.bak}'"
done | tee find.out
The find command finds the files you specify. The -print0 separates out the names of the files with a NUL symbol -- which is one of the few characters not allowed in a file name. The -d $\0means that your input separators are NUL symbols. See how nicely thefind -print0andread -d $'\0'` together?
You should almost never use the for file in $(*.bak) method. This will fail if the files have any white space in the name.
Notice that this command doesn't actually move any files. Instead, it produces a find.out file with a list of all the file renames. You should always do something like this when you do commands that operate on massive amounts of files just to be sure everything is fine.
Once you've determined that all the commands in find.out are correct, you can run it like a shell script:
$ bash find.out
rename .bak '' *.bak
(rename is in the util-linux package)
Caveat: there is no error checking:
#!/bin/bash
cd "$1"
for i in *.bak ; do mv -f "$i" "${i%%.bak}" ; done
You can always use the find command to get all the subdirectories
for FILENAME in `find . -name "*.bak"`; do mv --force "$FILENAME" "${FILENAME%.bak}"; done

Move files and rename - one-liner

I'm encountering many files with the same content and the same name on some of my servers. I need to quarantine these files for analysis so I can't just remove the duplicates. The OS is Linux (centos and ubuntu).
I enumerate the file names and locations and put them into a text file.
Then I do a for statement to move the files to quarantine.
for file in $(cat bad-stuff.txt); do mv $file /quarantine ;done
The problem is that they have the same file name and I just need to add something unique to the filename to get it to save properly. I'm sure it's something simple but I'm not good with regex. Thanks for the help.
Since you're using Linux, you can take advantage of GNU mv's --backup.
while read -r file
do
mv --backup=numbered "$file" "/quarantine"
done < "bad-stuff.txt"
Here's an example that shows how it works:
$ cat bad-stuff.txt
./c/foo
./d/foo
./a/foo
./b/foo
$ while read -r file; do mv --backup=numbered "$file" "./quarantine"; done < "bad-stuff.txt"
$ ls quarantine/
foo foo.~1~ foo.~2~ foo.~3~
$
I'd use this
for file in $(cat bad-stuff.txt); do mv $file /quarantine/$file.`date -u +%s%N`; done
You'll get everyfile with a timestamp appended (in nanoseconds).
You can create a new file name composed by the directory and the filename. Thus you can add one more argument in your original code:
for ...; do mv $file /quarantine/$(echo $file | sed 's:/:_:g') ; done
Please note that you should replace the _ with a proper character which is special enough.

Removing 10 Characters of Filename in Linux

I just downloaded about 600 files from my server and need to remove the last 11 characters from the filename (not including the extension). I use Ubuntu and I am searching for a command to achieve this.
Some examples are as follows:
aarondyne_kh2_13thstruggle_or_1250556383.mus should be renamed to aarondyne_kh2_13thstruggle_or.mus
aarondyne_kh2_darknessofunknow_1250556659.mp3 should be renamed to aarondyne_kh2_darknessofunknow.mp3
It seems that some duplicates might exist after I do this, but if the command fails to complete and tells me what the duplicates would be, I can always remove those manually.
Try using the rename command. It allows you to rename files based on a regular expression:
The following line should work out for you:
rename 's/_\d+(\.[a-z0-9A-Z]+)$/$1/' *
The following changes will occur:
aarondyne_kh2_13thstruggle_or_1250556383.mus renamed as aarondyne_kh2_13thstruggle_or.mus
aarondyne_kh2_darknessofunknow_1250556659.mp3 renamed as aarondyne_kh2_darknessofunknow.mp3
You can check the actions rename will do via specifying the -n flag, like this:
rename -n 's/_\d+(\.[a-z0-9A-Z]+)$/$1/' *
For more information on how to use rename simply open the manpage via: man rename
Not the prettiest, but very simple:
echo "$filename" | sed -e 's!\(.*\)...........\(\.[^.]*\)!\1\2!'
You'll still need to write the rest of the script, but it's pretty simple.
find . -type f -exec sh -c 'mv {} `echo -n {} | sed -E -e "s/[^/]{10}(\\.[^\\.]+)?$/\\1/"`' ";"
one way to go:
you get a list of your files, one per line (by ls maybe) then:
ls....|awk '{o=$0;sub(/_[^_.]*\./,".",$0);print "mv "o" "$0}'
this will print the mv a b command
e.g.
kent$ echo "aarondyne_kh2_13thstruggle_or_1250556383.mus"|awk '{o=$0;sub(/_[^_.]*\./,".",$0);print "mv "o" "$0}'
mv aarondyne_kh2_13thstruggle_or_1250556383.mus aarondyne_kh2_13thstruggle_or.mus
to execute, just pipe it to |sh
I assume there is no space in your filename.
This script assumes each file has just one extension. It would, for instance, rename "foo.something.mus" to "foo.mus". To keep all extensions, remove one hash mark (#) from the first line of the loop body. It also assumes that the base of each filename has at least 12 character, so that removing 11 doesn't leave you with an empty name.
for f in *; do
ext=${f##*.}
new_f=${base%???????????.$ext}
if [ -f "$new_f" ]; then
echo "Will not rename $f, $new_f already exists" >&2
else
mv "$f" "$new_f"
fi
done

Change Names of Multiple Files Linux

I have a number of files with names a1.txt, b1.txt, c1,txt...on ubuntu machine.
Is there any quick way to change all file names to a2.txt, b2.txt, c2.txt...?
In particular, I'd like to replace part of the name string. For instance, every file name contains a string called "apple" and I want to replace "apple" with "pear" in all file names.
Any command or script?
without any extra software you can:
for FILE in *1.txt; do mv "$FILE" $(echo "$FILE" | sed 's/1/2/'); done
for f in {a..c}1.txt; do echo "$f" "${f/1/2}"; done
replace 'echo' with 'mv' if the output looks correct.
and I want to replace "apple" with "linux"
for f in *apple*; do mv "$f" "${f/apple/linux}"; done
The curly brackets in line 1 should work with bash at least.
The following command will rename the specified files by replacing the first occurrence of 1 in their name by 2:
rename 1 2 *1.txt
ls *1.txt | perl -ne 'chomp; $x = $_; $x =~ s/1/2/; rename $_, $x;'
Here's another option that worked for me (following the examples above) for files in different subdirectories
for FILE in $(find . -name *1.txt); do mv "$FILE" "${FILE/1/2}"; done;
Something like this should work:
for i in *1.txt; do
name=$(echo $i | cut -b1)
mv $i ${name}2.txt
done
Modify to suit your needs.

Resources