Rename several files in the BASH - bash

I would like to rename files numbering: I have a files with '???' format I need to put them in '????'.
myfile_100_asd_4 to myfile_0100_asd_4
Thanks
Arman.
Not so elegant SOLUTION:
#/bin/bash
snap=`ls -t *_???`
c=26
for k in $snap
do
end=${k}
echo mv $k ${k%_*}_0${k##*_}_asd_4
(( c=c-1 ))
done
This works for me because I have myfile_100 files as well.

Use rename, a small script that comes with perl:
rename 's/(\d{3})/0$1/g' myfile_*
If you pass it the -n parameter before the expression it only prints what renames it would have done, no action is taken. This way you can verify it works ok before you rename your files:
rename -n 's/(\d{3})/0$1/g' myfile_*

just use the shell,
for file in myfile*
do
t=${file#*_}
f=${file%%_*}
number=$(printf "%04d" ${t%%_*})
newfile="${f}_${number}_${t#*_}"
echo mv "$file" "$newfile"
done

There's a UNIX app called ren (manpage) which supports renaming multiple files using search and substitution patterns. You should be able to cobble together a pattern that will inject that extra 0 into the filename.
Edit: Project page w/ download link can be found at Freshmeat.

Try:
for file in `ls my*`
do
a=`echo $file | cut -d_ -f1`
b=`echo $file | cut -d_ -f2`
c=`echo $file | cut -d_ -f3,4`
new=${a}_0${b}_${c}
mv $file $new
done

Related

Rename files to new naming convention in bash

I have a directory of files with names formatted like
01-Peterson#2x.png
15-Consolidated#2x.png
03-Brady#2x.png
And I would like to format them like
PETERSON.png
CONSOLIDATED.png
BRADY.png
But my bash scripting skills are pretty weak right now. What is the best way to go about this?
Edit: my bash version is 3.2.57(1)-release
This will work for files that contains spaces (including newlines), backslashes, or any other character, including globbing chars that could cause a false match on other files in the directory, and it won't remove your home file system given a particularly undesirable file name!
for old in *.png; do
new=$(
awk 'BEGIN {
base = sfx = ARGV[1]
sub(/^.*\./,"",sfx)
sub(/^[^-]+-/,"",base)
sub(/#[^#.]+\.[^.]+$/,"",base)
print toupper(base) "." sfx
exit
}' "$old"
) &&
mv -- "$old" "$new"
done
If the pattern for all your files are like the one you posted, I'd say you can do something as simple as running this on your directory:
for file in `ls *.png`; do new_file=`echo $file | awk -F"-" '{print $2}' | awk -F"#" '{n=split($2,a,"."); print toupper($1) "." a[2]}'`; mv $file $new_file; done
If you fancy learning other solutions, like regexes, you can also do:
for file in `ls *.png`; do new_file=`echo $file | sed "s/.*-//g;s/#.*\././g" | tr '[:lower:]' '[:upper:]'`; mv $file $new_file; done
Testing it, it does for example:
mv 01-Peterson#2x.png PETERSON.png
mv 02-Bradley#2x.png BRADLEY.png
mv 03-Jacobs#2x.png JACOBS.png
mv 04-Matts#1x.png MATTS.png
mv 05-Jackson#4x.png JACKSON.png

How to rename numbered files to begin and increase sequentially from one?

Given a directory of files:
00012.png, 00013.png, 00014.png etc...
What is the simplest way to rename the entire batch to:
00001.png, 00002.png, 00003.png etc...
I've looked up the rename utility but am feeling baffled.
There a number of other questions similar in nature to this but they are very specific (e.g: "how do I remove this underscore and three random letters"), and so they're normally answered with a similar degree of specificity. I just can't find a solution to this precise problem.
If you just want to number the files, use a simple counter:
# set counter to zero
i=0
for file in *png; do
# move file
echo mv "$file" "$(printf "%05d.png" ${i})"
# increase counter
((i++))
done
With given filenames 00012.png 00013.png 00014.png this results in
mv 00012.png 00000.png
mv 00013.png 00001.png
mv 00014.png 00002.png
Please remove the echo, i just added it for testing.
Would try something like this:
ls *.png | while read file; do
mv "$file" "$(printf %05d $(expr $(echo $file | cut -d. -f1) - 11)).png"
done;
(you may replace "mv" by "echo" for testing purpose)
$ touch 00012.png 00013.png 00014.png
$ ls *.png | while read file; do echo "$file" "$(printf %05d $(expr $(echo $file | cut -d. -f1) - 11)).png";done;
00012.png 00001.png
00013.png 00002.png
00014.png 00003.png

get the file name that has specific extension in shell script

I have three files in a directory that has the structure like this:
file.exe.trace, file.exe.trace.functions and file.exe.trace.netlog
I want to know how can I get file.exe as file name?
In other world I need to get file name that has the .trace extension? I should note that as you can see all the files has the .trace part.
If $FILENAME has the name, the root part can be gotten from ${FILENAME%%.trace*}
for FILENAME in *.trace; do
echo ${FILENAME%%.trace*}
done
You can also use basename:
for f in *.trace; do
basename "$f" ".trace"
done
Update: The previous won't process files with extra extensions besides .trace like .trace.functions, but the following sed will do:
sed -r 's_(.*)\.trace.*_\1_' <(ls -c1)
You can also use it in a for loop instead:
for f in *.trace*; do
sed -r 's_(.*)\.trace.*_\1_' <<< "$f"
done
Try:
for each in *exe*trace* ; do echo $each | awk -F. '{print $1"."$2}' ; done | sort | uniq

change lowercase file names to uppercase with awk ,sed or bash

I would like to change lowercase filenames to uppercase with awk/sed/bash
your help would be appreciated
aaaa.txt
vvjv.txt
acfg.txt
desired output
AAAA.txt
VVJV.txt
ACFG.txt
PREFACE:
If you don't care about the case of your extensions, simply use the 'tr' utility in a shell loop:
for i in *.txt; do mv "$i" "$(echo "$i" | tr '[a-z]' '[A-Z]')"; done
If you do care about the case of the extensions, then you should be aware that there is more than one way to do it (TIMTOWTDI). Personally, I believe the Perl solution, listed here, is probably the simplest and most flexible solution under Linux. If you have multiple file extensions, simply specify the number you wish to keep unchanged. The BASH4 solution is also a very good one, but you must be willing to write out the extension a few times, or alternatively, use another variable to store it. But if you need serious portability then I recommend the last solution in this answer which uses octals. Some flavours of Linux also ship with a tool called rename that may also be worth checking out. It's usage will vary from distro to distro, so type man rename for more info.
SOLUTIONS:
Using Perl:
# single extension
perl -e 's/\.[^\.]*$/rename $_, uc($`) . $&/e for #ARGV' *.txt
# multiple extensions
perl -e 's/(?:\.[^\.]*){2}$/rename $_, uc($`) . $&/e for #ARGV' *.tar.gz
Using BASH4:
# single extension
for i in *.txt; do j="${i%.txt}"; mv "$i" "${j^^}.txt"; done
# multiple extensions
for i in *.tar.gz; do j="${i%.tar.gz}"; mv "$i" "${j^^}.tar.gz"; done
# using a var to store the extension:
e='.tar.gz'; for i in *${e}; do j="${i%${e}}"; mv "$i" "${j^^}${e}"; done
Using GNU awk:
for i in *.txt; do
mv "$i" $(echo "$i" | awk '{ sub(/.txt$/,""); print toupper($0) ".txt" }');
done
Using GNU sed:
for i in *.txt; do
mv "$i" $(echo "$i" | sed -r -e 's/.*/\U&/' -e 's/\.TXT$/\u.txt/');
done
Using BASH3.2:
for i in *.txt; do
stem="${i%.txt}";
for ((j=0; j<"${#stem}"; j++)); do
chr="${stem:$j:1}"
if [[ "$chr" == [a-z] ]]; then
chr=$(printf "%o" "'$chr")
chr=$((chr - 40))
chr=$(printf '\'"$chr")
fi
out+="$chr"
done
mv "$i" "$out.txt"
out=
done
In general for lowercase/upper case modifications "tr" ( translate characters ) utility is often used, it's from the set of command line utilities used for character replacement.
dtpwmbp:~ pwadas$ echo "xxx" | tr '[a-z]' '[A-Z]'
XXX
dtpwmbp:~ pwadas$
Also, for renaming files there's "rename" utility, delivered with perl ( man rename ).
SYNOPSIS
rename [ -v ] [ -n ] [ -f ] perlexpr [ files ]
DESCRIPTION
"rename" renames the filenames supplied according to the rule specified as the first argument. The perlexpr argument is a Perl expression which is expected to modify the $_ string in
Perl for at least some of the filenames specified. If a given filename is not modified by the expression, it will not be renamed. If no filenames are given on the command line,
filenames will be read via standard input.
For example, to rename all files matching "*.bak" to strip the extension, you might say
rename 's/\.bak$//' *.bak
To translate uppercase names to lower, you'd use
rename 'y/A-Z/a-z/' *
I would suggest using rename, if you only want to uppercase the filename and not the extension, use something like this:
rename -n 's/^([^.]*)\.(.*)$/\U$1\E.$2/' *
\U uppercases everything until \E, see perlreref(1). Remove the -n when your happy with the output.
Bash 4 parameter expansion can perform case changes:
for i in *.txt; do
i="${i%.txt}"
mv "$i.txt" "${i^^?}.txt"
done
bash:
for f in *.txt; do
no_ext=${f%.txt}
mv "$f" "${no_ext^^}.txt"
done
for f in *.txt; do
mv "$f" "`tr [:lower:] [:upper:] <<< "${f%.*}"`.txt"
done
An easier, lightweight and portable approach would be:
for i in *.txt
do
fname=$(echo $i | cut -d"." -f1 | tr [a-z] [A-Z])
ext=$(echo $i | cut -d"." -f2)
mv $i $fname.$ext
done
This would work on almost every version of BASH since we are using most common external utilities (cut, tr) found on every Unix flavour.
Simply use (on terminal):
for i in *.txt; do mv $i `echo ${i%.*} | tr [:lower:] [:upper:]`.txt; done;
This might work for you (GNU sed):
printf "%s\n" *.txt | sed 'h;s/[^.]*/\U&/;H;g;s/\(.*\)\n/mv -v \1 /' | sh
or more simply:
printf "%s\n" *.txt | sed 'h;s/[^.]*/\U&/;H;g;s/\(.*\)\n/mv -v \1 /e'
for i in *.jar; do mv $i `echo ${i%} | tr [:upper:] [:lower:]`; done;
this works for me.

Renaming files in a UNIX directory - shell scripting

I have been trying to write a script that will take the current working directory, scan every file and check if it is a .txt file. Then take every file (that's a text file), and check to see if it contains an underscore anywhere in its name and if it does to change the underscore to a hyphen.
I know that this is a tall order, but here is the rough code I have so far:
#!/bin/bash
count=1
while((count <= $#))
do
case $count in
"*.txt") sed 's/_/-' $count
esac
((count++))
done
What I was thinking is that this would take the files in the current working directory as the arguments and check every file(represented by $count or the file at "count"). Then for every file, it would check if it ended in .txt and if it did it would change every underscore to a hyphen using sed. I think one of the main problems I am having is that the script is not reading the files from the current working directory. I tried included the directory after the command to run the script, but I think it took each line instead of each file (since there are 4 or so files on every line).
Anyway, any help would be greatly appreciated! Also, I'm sorry that my code is so bad, I am very new to UNIX.
for fname in ./*_*.txt; do
new_fname=$(printf '%s' "$fname" | sed 's,_,-,')
mv "$fname" "$new_fname"
done
why not:
rename 's/_/-/' *.txt
$ ls *.txt | while read -r file; do echo $file |
grep > /dev/null _ && mv $file $(echo $file | tr _ -); done
(untested)
Thanks for all your input guys! All in all, I think the solution I found was the most appropriate for my skill level was:
ls *.txt | while read -r file; do echo file |
mv $file $(echo $file | sed 's,_,-,');
done
This got what I needed done, and for my purposes I am not too worried about the spaces. But thanks for all your wonderful suggestions, you are all very intelligent!

Resources