0

Now I have the rename script like this:

cd /Users/KanZ/Desktop/Project/Test/ 
n=1
for file in *.jpg; do 
    echo $file
    prefix=M
    file_name=M$n.jpg 
    echo $file_name
    n=$(( $n+1 ))
    mv $file $file_name 
done 

The first if I run script, the all of jpg files will be M1.jpg M2.jpg M3.jpg but if I add the new file name A1.jpg to this directory and run script again. All of M1.jpg M2.jpg M3.jpg will be replaced by M4.jpg(before run script, this file named A1.jpg) because the first letter is A. It come before M. This is my problem. I would like to get M1 M2 M3 M4.jpg and every time if there are new files coming, this script will generate the continue name like M5.jpg M6.jpg . How is the code look like? Hope you understand that. Thank u for helping

gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
kantawit
  • 101
  • 1
  • 1
  • 6
  • Your script looks pretty broken; I think something went wrong when you were copying and pasting it here. In particular, it seems to be missing some necessary line-breaks. – ruakh Dec 23 '12 at 03:24
  • Check out [Guard](https://github.com/guard/guard) – ocodo Dec 23 '12 at 08:21

3 Answers3

0

The other answers given so far don't show you any good practice.

Here's one possibility that assumes that the numbering is continuous (i.e., no jump from M4.jpg to M6.jpg). Without that assumption, the script is safe (it won't overwrite existing files, but will not rename certain files).

#!/bin/bash

shopt -s extglob
shopt -s nullglob

cd /Users/KanZ/Desktop/Project/Test/

# Determine how many files MX.jpg you have (with X a number):
files=( M+([[:digit:]]).jpg )
n=${#files[@]}

for file in !(M+([[:digit:]])).jpg; do
    file_name=M$((++n)).jpg
    mv -vn -- "$file" "$file_name"
done
  • The -n option to mv: no clobber (do not overwrite an already existing file)
  • The -v option to mv: be verbose (so you don't need the echos you had)
  • The -- thing: end of options, only arguments will be found behind (just in case some files will start with a hyphen, that would confuse mv).
gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
-1

The way i understood your requirement is :

Change all the .jpg file names from what ever name they have to M*.jpg with an incremental number following M.

During multiple runs of the program the count should increase from the highest value of M file that was setup during the last run. For example if the first run of the program created M1, M2, M3 and then you add more files they should start from M4, M5, M6.

But the M1, M2, M3 itself should not be changed.

So a couple of suggestions :

you are setting n=1 at the start of the script. You should use the highest value of Mx.jpg that exists in the file from the previous run.

Second, when you are looking for files and iterating them, exclude all M*.jpg files, so that their names are not replaced.

Do you think this is your requirement. If you have any additional inputs please add a comment. Will send out the script in the next comment.

Test Cases : Existing Files, X.jpg, ASG.jpg, GER.jpg File names after the run : M1.jpg, M2.jpg, M3.jpg

If you just run the script once more after the first run with no additional files: There should not be any change in the file names : M1.jpg, M2.jpg, M3.jpg.

Now Add more files : Z.jpg, A.jpg, B.jpg The file names should be changed as follows :

M1.jpg => M1.jpg, M2.jpg => M2.jpg, M3.jpg => M3.jpg, A.jpg => M4.jpg, B.jpg => M5.jpg, Z.jpg => M6.jpg. So the file names will be M1.jpg, M2.jpg, M3.jpg, M4.jpg, M5.jpg, M6jpg.

kcsarath
  • 54
  • 3
  • Yeah everything that u think is correct!! Thank you for understand me and help me. can u give me a code because I don't understand about how to write shell script. – kantawit Dec 23 '12 at 03:33
  • n=`ls -l M*.jpg | wc -l`; n=$(( $n+1 ));echo $n for file in `ls *.jpg | grep -v "M.*\.jpg"` ; do echo $file prefix=0M file_name=M$n.jpg echo $file_name n=$(( $n+1 )) mv $file $file_name done – kcsarath Dec 23 '12 at 03:43
  • @gniourf_gniourf There is nothing inherently bad about parsing the output of a command, including ls. If you have a constructive comment about why a particular method of parsing the output is less effective or is particularly troublesome, please say that. Don't just state an opinion of something being "bad". Insulting is generally not a good way to influence people. – Tony K. Dec 24 '12 at 03:50
  • Parsing the output of `ls` in a `for` loop is broken as soon as a file name contains a space. Piping the output of ls through another command is broken as soon as a file name contains a newline character. These practices are really bad (and I wish they would totally disappear from the internet) especially since there exists robust (and more efficient) solutions, e.g., glob. – gniourf_gniourf Dec 24 '12 at 09:00
-1

This little script will do it.

cd /Users/KanZ/Desktop/Project/Test/ 
n=$(ls -1 | grep '^M' -c)                    # find the number for M files 
ls -1 *.jpg| grep -v '^M' | while read file  # for each of the non-M files
do 
   n=$(($n+1));                       
   new_file=M$n.jpg                          # new name with next available M file name
   mv "$file" "$new_file"                        # rename with new file name
done 

See how it works.

test/rename$ for x in 1 2 3; do echo A$x> A$x.jpg; done;
test/rename$ ls
A1.jpg  A2.jpg  A3.jpg
test/rename$ cat ../rnm.sh 
#!/bin/bash
cd "$1"
n=$(ls -1 | grep '^M' -c)
nfiles=$(ls -1 *.jpg| grep -v '^M');
for file in $nfiles;
do 
   n=$(($n+1));
   new_file=M$n.jpg
   mv $file $new_file
done 
test/rename$ bash ../rnm.sh  ./
test/rename$ ls
M1.jpg  M2.jpg  M3.jpg
test/rename$ for x in 1 2 ; do echo B$x> B$x.jpg; done;
test/rename$ ls
B1.jpg  B2.jpg  M1.jpg  M2.jpg  M3.jpg
test/rename$ bash ../rnm.sh  ./
test/rename$ ls
M1.jpg  M2.jpg  M3.jpg  M4.jpg  M5.jpg
test/rename$ for x in *.jpg; do echo $x; cat $x; done;
M1.jpg
A1
M2.jpg
A2
M3.jpg
A3
M4.jpg
B1
M5.jpg
B2
Shiplu Mokaddim
  • 56,364
  • 17
  • 141
  • 187