Renaming by manipulating strings

hello

does someone want to help me for this one ?

i want to rename file by inversing parts of filenames separated by the delimiter "--"

sometimes filenames have three strings :

aabb4ccdd eeffgg -- 5566 -- aa78bb ccd eef gghhi.ext    

to

aa78bb ccd eef gghhi -- 5566 -- aabb4ccdd eeffgg.ext
aabbcc -- 55 -- aab667ccdd ee.ext                        

to

aab667ccdd ee -- 55 -- aabbcc.ext
556aa -- aabb -- 7788.ext                                

to

7788 -- aabb -- 556aa.ext

sometimes there are only two strings :

aabbccdd eef -- gghh iijjkkl.ext  

to

gghh iijjkkl -- aabbccdd eef.ext

when there are two strings i think the solution is to inverse strings separated by "--"

i've got filename like these one too, i'd like to put the digits at at the end to the beginning :

aabbccdde -- ffgghh iijjkkll5566778.ext      

to

5566778 aabbccdde -- ffgghh iijjkkll.ext
aab55c -- ddeeffgghh5566.ext   

to

5566 aab55c -- ddeeffgghh.ext

thanks for you help !

for above two case try this...

for i in *.ext
do
file_name=$(echo "$i" | awk -F " -- " '{split($NF,a,".");s=$1;$1=a[1];$(NF)=s"."a[2]}1' OFS=" -- ")
mv $i $file_name
done

for last having numeric at the end of file..

for i in *[0-9].ext
do
file=$(echo "$i" | awk -F "" '{for(i=1;i<=NF;i++){if($i ~ /[A-z]/){s=""}else{if($i == "."){print s}else{s=s?s""$i:$i}}}}')
file_name=$(echo "$i" | awk -v RPL="$file" '{sub(RPL,"",$0);print RPL,$0}')
mv $i $file_name
done
1 Like

1>Verify is these are the conditions you require by just printing the mv command

ls *ext | perl -F"--" -alne '{if($#F==1){
if($F[1]=~/(\d+).ext/){ $p=$1;$F[0]=~s/^/$p /g;$F[1]=~s/$p//;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;}
else { ($F[0],$F[1])=($F[1],$F[0]);$F[0]=~s/.ext//;$F[1]=~s/ *$/(.ext|^ *)/;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;}
}else{ ($F[0],$F[2])=($F[2],$F[0]);$F[0]=~s/.ext//;$F[2]=~s/ *$/(.ext|^ *)/;;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;}
}'

2>Once you are sure of what you want execute it

ls *ext | perl -F"--" -alne '{if($#F==1){
if($F[1]=~/(\d+).ext/){ $p=$1;$F[0]=~s/^/$p /g;$F[1]=~s/$p//;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;}
else { ($F[0],$F[1])=($F[1],$F[0]);$F[0]=~s/(.ext|^ *)//;$F[1]=~s/ *$/.ext/;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;}
}else{ ($F[0],$F[2])=($F[2],$F[0]);$F[0]=~s/(.ext|^ *)//;$F[2]=~s/ *$/.ext/;;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;}
}' | sh
1 Like
for i in *[0-9].ext 
do 
file=$(echo "$i" | awk -F "" '{for(i=1;i<=NF;i++){if($i ~ /[A-z]/){s=""}else{if($i == "."){print s}else{s=s?s""$i:$i}}}}') 
file_name=$(echo "$i" | awk -v RPL="$file" '{sub(RPL,"",$0);print RPL,$0}') 
mv $i $file_name 
done

maybe your script works but my level of understandings don't allow me to tell you anything on it !

Is there any reason why all of that code is on a single line? Do you think that helps your 'level of understanding'?

For me, it's unreadable.

edit: you updated it. It's marginally more readable. :slight_smile:

ls *ext | perl -F"--" -alne '{if($#F==1){ 
if($F[1]=~/(\d+).ext/){ $p=$1;$F[0]=~s/^/$p /g;$F[1]=~s/$p//;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;} 
else { ($F[0],$F[1])=($F[1],$F[0]);$F[0]=~s/(.ext|^ *)//;$F[1]=~s/ *$/.ext/;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;} 
}else{ ($F[0],$F[2])=($F[2],$F[0]);$F[0]=~s/(.ext|^ *)//;$F[2]=~s/ *$/.ext/;;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;} 
}' | sh

for moving numeric to the beginning, this script works perfectly !

???
i have a question can the script is capable to rename directories

If i don't understand any script which have lot of conditions and scenarios, I prefer to test script part by part. Divide script into multiple pieces so it can be understandable.. Run script part by part....:slight_smile:

Please read this

the directories looks like this :

aabbccdde -- ffgghh iijjkkll5566778

to

5566778 aabbccdde -- ffgghh iijjkkll

sometimes there's only one string

aab55ccddeeffgghh6677

to

6677 aab55ccddeeffgghh

thanks !

No my script doesn't work for these directories you have mentioned since its different conditions all together....But you can use the logic in my script as a workaround ..let me know if any help required in the same..

1 Like

Try shell only:

for file in *.ext
do
  first=${file%% -- *}
  secondext=${file##* -- }
  second=${secondext%.*}
  ext=${file##*.}
  middle=${file#$first}
  middle=${middle%$secondext}
  mv "$file" "$second$middle$first.$ext"
done
1 Like

that's what i want to ask you after the precision, do you want to help to understand a little bit of your script

what are the meaning of

 
$p
$1
$F[0]
$F[1]

Your requirement seems to have changed. There is no separator in the second example ?
And the first example does not switch left and right side...

1 Like

for inversing strings delimited by "--" in filenames, this script works perfectly !

that put the last string to the beginning & vice versa

---------- Post updated at 07:12 PM ---------- Previous update was at 06:15 PM ----------

thanks for your perspicacity ! you're right i've found a solution when there are only one string
i add " -- " at the end to fits the script

so don't take that example (aab55ccddeeffgghh6677)

i only need want to know if the script works for the directories

i've checked the mv command page and adding "-t" option perhaps may help

but i don't quite sure and i don't know if it fit in the script

ls *ext | perl -F"--" -alne '{if($#F==1){
if($F[1]=~/(\d+).ext/){ $p=$1;$F[0]=~s/^/$p /g;$F[1]=~s/$p//;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;}
else { ($F[0],$F[1])=($F[1],$F[0]);$F[0]=~s/(.ext|^ *)//;$F[1]=~s/ *$/.ext/;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;}
}else{ ($F[0],$F[2])=($F[2],$F[0]);$F[0]=~s/(.ext|^ *)//;$F[2]=~s/ *$/.ext/;;print "mv \"$_\" \"".join(" -- ",@F)."\"" ;}
}' | sh

Ok.
1>First store all the necessary directory names into one file like "temp" and execute as usual to check if this is satisfying your conditions

perl -lne '{$Tget=$_;$_=~s/(.*?)(\d+)$/$2 $1/g;print "mv \"$Tget\" \"$_\""}' temp
mv "aabbccdde -- ffgghh iijjkkll5566778" "5566778 aabbccdde -- ffgghh iijjkkll"
mv "aab55ccddeeffgghh6677" "6677 aab55ccddeeffgghh"

2>Execute the same now

perl -lne '{$Tget=$_;$_=~s/(.*?)(\d+)$/$2 $1/g;print "mv \"$Tget\" \"$_\""}' temp | sh

---------- Post updated at 01:23 PM ---------- Previous update was at 01:14 PM ----------

And one more thing...
normal mv works for directories also...you don't have to use any option unless some peculiar case which i may not have come across...

-t option is invalid usage here. This is what man page says :

       -t, --target-directory=DIRECTORY
              move all SOURCE arguments into DIRECTORY

which means moving(not renaming) multiple files into a directory.

1 Like

Hi msabhi, perl does have a file rename operator, if you'd forgotten about it.

1 Like

Right elixir...new to PERL workarounds for files..somehow forgot its usage:wall:
Below code would be more efficient...:b:

perl -lne '{$Tget=$_;$_=~s/(.*?)(\d+)$/$2 $1/g;rename "$Tget", "$_"}' temp

1 Like

thanks for your helpings to all, i really appreciate it !