Multifile rename Bash script issue - bash

I was using a code to rename files and a very interesting problem emerged: It worked in a computer running Mac OSX Lion 10.7.5, but it failed on Mac OSX 10.6.8 Snow Leopard.
The code is:
for i in *; do mv $i `echo $i | sed 's/..//'`; done
and the error I got is:
usage: mv [-f | -i | -n] [-v] source target
mv [-f | -i | -n] [-v] source ... directory
It's very weird because mv is working normally if not in a for loop...
Anyone know what should I do to get it working?

You should use bash string substitution:
for i in *; do mv $i ${i/??/}; done
or
for i in *; do mv $i ${i#??}; done

If you have files with spaces (or certain other shell metachaarcters) it's critical that you put all variable references in double-quotes. Otherwise, if you have e.g. i="File Name.txt", you'll be running a command like mv File Name.txt le Name.txt and it'll think you're specifying 4 filenames not just 2. The other standard mistake (which you're not making) is using for file in $(ls), which gets confused by spaces before the names even make it into the variable.
Also, I'm a bit concerned about short filenames and name conflicts. Even if you think you don't have any short filenames, if you have the dotglob shell option set you'll wind up trying to rename the pseudo-files "." and "..", which won't go well at all. Also, if you have e.g. files named "abcdefg" and "cdefg", the script will rename the first over the second (silently erasing the second), then rename that to "efg".
So, here's my proposed rewrite (also using #TrueY's suggestion for shortening the filename):
for i in *; do
if [ ${#i} -le 2 ]; then
echo "$i: not renamed (too short)" >&2
elif [ -e "${i:2}" ]; then
echo "$i: not renamed (${i:2} already exists)" >&2
else
mv "$i" "${i:2}"
fi
done

Related

Batch renaming files in MAC OSX

I have several thousand files with name like this:
PIN_PMN_PT_010_02_00331_0004_018edf
and need to rename them all something like this:
PIN_PMN_PT_010_02_00331_0004_018.edf
I have used simple mv scripts like this:
for f in *; do echo mv "$f" "`echo $f | tr 'edf' '.edf'`"; done
For some reason it creates names like this:
PIN_PMN_PT_010_02_00331_0004_018.ed
They are missing the last f. I am running the script using echo to dry run. Any ideas please?
Using MACBook Pro running Mohave 10.14.6 and Bash.
Use shell Parameter Expansion!
Simply under any shell:
For the test, echo to show what's will go:
for file in *edf ;do echo mv "$file" "${file%edf}.edf" ;done
Then, for doing the job:
for file in *edf ;do mv "$file" "${file%edf}.edf" ;done
(This must work same on MacOs, than under Linux.)
... And to prevent renaming of already correctly named files:
for file in *edf ;do test -f "${file##*.edf}" && mv "$file" "${file%edf}.edf" ;done
Syntax ${file##*.edf} will replace any string, terminated by .edf, by an empty string. So test -f "" will fail.
... Still: I don't have any Mac for doing the test, but as this is POSIX Standard, this must work on any shell. (Let my know, please comment!)
More infos?
Have a look at man sh or man bash and search for Parameter Expansion
man -P"less +'/Parameter Expansion'" bash
Using sed, this should work
for f in *; do echo mv "$f" "`echo $f | sed 's/.\{3\}$//`.edf"; done
You are just removing the last 3 characters of a string, and adding your file extension.
Personally, I find the rename command invaluable for this sort of thing:
rename 's/edf$/.edf/' *edf
If you want to do a dry-run, you can do:
rename --dry-run 's/edf$/.edf/' *edf
Sample Output
'PIN_PMN_PT_010_02_00331_0004_018edf' would be renamed to 'PIN_PMN_PT_010_02_00331_0004_018.edf'
The benefits of using rename are:
it can do a dry-run to test before you run for real
it will create all necessary directories with the -p option
it will not clobber (overwrite) files without warning
you have the full power of Perl available to you and can make your renaming as sophisticated as you wish.
As helpfully suggested by F. Hauri in the comments, you may have some files that have already had the dot inserted before the extension in your directory. To protect against insertion of a second dot, you could either be more specific in the files you select for renaming and only rename those ending in a digit followed by edf:
rename 's/edf$/.edf/' *[0-9]edf
Or, as F.Hauri suggested:
rename 's/([^.])edf$/$1.edf/' *edf
Note that you can install on macOS with homebrew:
brew install rename

Shell: Check If File Exists When Changing Format

I'm trying to write a script that, when run, renames all .htm files in the directory to .html for a server. NO PROBLEM!
for file in *.htm ; do mv $file `echo $file | sed 's/\(.*\.\)htm/\1html/'` ; done
However, if there is a .html equivalent of a file already, it should print out "$file.html already converted - contacted administrator" and exit with status 1
I've tried using -mv and exists, but no cigar. Any help appreciated.
You should first check for the file, then try to rename it by moving.
Something like this should suffice:
for file in *.htm; do
[ -f "${file%.*}.html" ] && mv "${file}" "${file%.*}.html" || printf "%s.html already converted - contacted administrator" "${file%.*}"
done
Note that also without any substitution you can just do mv "${file}" "${file}l".
Note that if do not use an amministrative user it is safer using an if-then-else as follows:
for file in *.htm; do
if [ -f "${file%.*}.html" ]; then
mv "${file}" "${file%.*}.html"
else
printf "%s.html already converted - contacted administrator" "${file%.*}"
fi
done

A simple mv command in a BASH script

The aim of my script:
look at all the files in a directory ($Home/Music/TEST) and its sub-directories (they are music files)
find out what music genre each file belongs to
if the genre is Heavy, then move the file to another directory ($Home/Music/Output)
This is what I have:
#!/bin/bash
cd Music/TEST
for files in *
do
if [ -f "$files" ];then
# use mminfo to get the track info
genre=`mminfo "$files"|grep genre|awk -F: '{print $2}'|sed 's/^ *//g'|sed 's/[^a-zA-Z0-9\ \-\_]//g'`
if [ $genre = Heavy ] ;then
mv "$files" "~/Music/Output/$files"
fi
fi
done
Please tell me how to write the mv command. Everything I have tried has failed. I get errors like this:
mv: cannot move ‘3rd Eye Landslide.mp3’ to ‘/Music/Output/3rd Eye Landslide.mp3’: No such file or directory
Please don't think I wrote that mminfo line - that's just copied from good old Google search. It's way beyond me.
Your second argument to mv appears to be "~/Music/Output/$files"
If the ~ is meant to signify your home directory, you should use $HOME instead, like:
mv "$files" "$HOME/Music/Output/$files"
~ does not expand to $HOME when quoted.
By the look of it the problem occurs when you move the file to its destination.Please check that /Music/Output/ exits from your current directory.Alternatively use the absolute path to make it safe. Also it's a good idea not use space in the file-name.Hope this will helps.:)
Put this command before mv command should fix your problem.
mkdir -p ~/Music/Output

Need help writing bash script to move folders around

What i need to do is replace the folder amtlib.framework into each Adobe app on my mac
if i do:
cd /Applications; ls | grep Adobe, this gives me all the folders which i need
here's some pseudo code:
apps = ls | grep Adobe
for each x in apps
if (x/x.app/contents/frameworks/amtlib.framwork) //if this folder exists
add .bak extension //amtlib.framework.bak
copy ~/Downloads/.../amtlib.framwork to x/x.app/contents/frameworks/
how would i implement this as a bash script?
Something like
for x in $( ls | grep Adobe) ; do
if [[ -d "${x}"/"${x}".app/contents/frameworks/amtlib.framwork ]] ; then
# add .bak extension # //amtlib.framework.bak
#? mkdir "${x}"/"${x}".app/contents/frameworks/amtlib.framwork.bak
#? /bin/mv "${x}"/"${x}".app/contents/frameworks/amtlib.framwork {x}/${x}.app/contents/frameworks/amtlib.framwork.bak
/bin/cp ~/Downloads/.../amtlib.framwork to "${x}"/"${x}".app/contents/frameworks/
else
: # ??? what do you want to do if there's not
fi
done # loop
If you're likely to have spaces in your dirnames, (not sure if OSX support -print0), but try
find . -name 'Adobe' -print0 \
| while read x ; do
if ....
As an FYI, assignments in bash are done like (without spaces around the =):
apps=$(ls | grep Adobe)
Depending on the situation then, you'll want to use "$apps", or just plain $apps, which leaves each word in the list as a separate token. (If there are spaces in your filename or path, 1 path/file is now 2 words, and will cause issues). There are also array notations to use, apps=( $(ls | grep Adobe) ), and using those vars like ${#apps[#]} (number of elems), ${apps[#]} (all elems), ${apps[1]}, (first elem) is possible.
Also, it's not clear what your intent with add .bak extension is for. My best guess is my 2nd option, /bin/mv ... .bak.
IHTH.
First of all there's a typo error in the original post that's made its way throughout the examples given. The folder you are looking to rename/replace is amtlib.framework, not framwork.
Second, for some reason, the test for existence of the .bak directory is not working for me, even when I split this out to a separate if-then statement it doesn't work:
cd /Applications
for x in *Adobe* ; do
printf "$x \n"
printf "%s" " "
if [ -d "$x/$x.app/contents/frameworks/amtlib.framework.bak" ]; then
printf "removing old bak... "
fi
if [ -d "$x/$x.app/contents/frameworks/amtlib.framework" ]; then
printf "moving... "
printf "copying... "
printf "%s\n" "done!"
else
printf "%s\n" "nothing to do here!"
fi
done
cd ~
Finally, understanding the goal you will fail to update a couple of apps that have an additional folder level (e.g., Acrobat Pro and Illustrator).

Using bash what scripts or commands do you use to make you more productive?

What scripts do you regularly use to improve your productivity?
Over the last year I have been trying to use bash scripts and commands to improve my productivity as a developer (Web and applications). Here is a list of a few simple ones that I use:
Make files lower case:
for i in *.txt; do mv "$i" "`echo $i| tr [A-Z] [a-z]`"; done
Test whether a tag exists in subversion:
if [ "`svn ls http://www.mysvnserver.co.uk/myproject/tags | grep it-0.7.0.1/`" = "it-0.7.0.1/" ]; then echo YES; else echo NO; fi
Rename all JPG files in the current directory and add an increment:
j=16;for i in *.jpg; do mv "$i" "gallery_"$j".jpg"; j=$(($j+1)); done;ls
Fix a misspelling in a group of filenames:
for i in aples*.jpg; do mv $i ${i/aples/apples} ; done
For more see here:
http://blog.emson.co.uk/2009/06/18-useful-bash-scripts-for-web-developers
What scripts do you use?
Thanks...
You have a good source of such command at CommandLineFu.

Resources