Click to See Complete Forum and Search --> : Is this possible to do with a shell script?
Silent Bob
09-23-2001, 02:53 AM
I am looking to get into shell scripting and this is a problem that I need to solve. I just would like to know if it is possible to do this with a shell script, otherwise I'll write a program to do it instead.
(You can skip the background info if you like)
Recently my dad was given a CD from a firm that uses Apples. First problem was that he couldn't read the CD in Windows so I booted into GNU/Linux and mounted it as an hfs device, all well and good.
Next I went to copy the contents on to a FAT partition so he could get at in windows. Problem was that the guys had named a load of directories/files with colons ":" in the file name, something that's not allowed in a windows filesystem.
(Actual Problem Here)
What I am looking to do is get a script that when given a starting directory will recursively go through the directory and replace every instance of one character (in file/directory names) with another one. The characters will be specified at the command line.
Sorry for the big long story. I am not looking for a full solution, just whether it is possible to do the above with a shell script and maybe a pointer or two on what to do to learn how to do this if it is.
Thanks in advance
Gnu/Vince
09-23-2001, 03:10 PM
This would probably be doable with a Perl script. I wouldn't know how to do it though. Search the boards for the mp3 renamer. You can probably get all the bits of code you need.
bdg1983
09-23-2001, 04:50 PM
it certainly is possible with shell scripts. Use ls -R and tr.
:)
[ 23 September 2001: Message edited by: Bradmont ]
The Kooman
09-24-2001, 01:07 AM
QUOTE]Originally posted by Silent Bob:
<STRONG>I am looking to get into shell scripting and this is a problem that I need to solve. I just would like to know if it is possible to do this with a shell script, otherwise I'll write a program to do it instead.
(Actual Problem Here)
What I am looking to do is get a script that when given a starting directory will recursively go through the directory and replace every instance of one character (in file/directory names) with another one. The characters will be specified at the command line.
</STRONG>[/QUOTE]
How 'bout this?
Warning: Untested code!
#!/bin/bash
#
# usage: replace-name pattern-character replacement-character [directory]
#
# if "directory" is not specified, then it starts at the current directory
# if only one pattern is specified, then that character is deleted.
#
# example: replace-name ':' '-' /home/some_user/
# or: replace-name ' ' '_'
#
pchar=$1 # pattern character
rchar=$2 # replacement character
topdir="$PWD" # start at current directory by default
pattern="'*$pchar*'"
if [ -n "$3" ]; then topdir="$3"; fi # user specified a directory
for i in `find $topdir -name $pattern`
do
x="`echo $i | sed 's/$pchar/$rchar/g'`"
echo "$i -> $x"
# uncomment the line below to actually do the changing!
# mv "$i" "$x"
done
Hope this works!
takshaka
09-25-2001, 03:06 AM
Here (http://www.cokesque.com/perl/pod.pl?file=/perl/oneliners/unspace.pod) is the one-liner I always give people with a question like this.
mrBen
09-25-2001, 04:03 AM
The link that takshaka gives is a short perl line that translates spaces into underscores, rather than fullstops. Should you not be familiar with Perl (and I'm not ;) ) change the tr bit from tr/ /_/ to tr/./_/ and it should do what you want. However, it doesn't allow you to select the characters you want to change as neatly as the shell script above.
Silent Bob
09-26-2001, 05:21 AM
Thanks for the help, this is what I came up with
(I was trying to avoid using sample code as much as possible)
#!/bin/bash
#Recursively replace a specified character in directory/file names
char=$1
newchar=$2
directory=$PWD
if [ -n $3 ]; then directory=$3; fi
#Change all file names/directory names in this level first
#If there is no change don't rename them
for element in `ls $directory`; do
x="`echo $element | tr $char $newchar`"
echo "$directory$element -> $directory$x"
(if [ "$x" != "$element" ]; then
mv $directory$element $directory$x;
fi);
done
#If there are directories in the specified starting directory
#then move into each one of those in turn
#if [ -d $directory*/ ]; then
listOfDirectories="`ls -d $directory*/`"
#fi
for entry in $listOfDirectories; do
$PWD/replace-char $char $newchar $entry;
done
I found that I couldn't use ls -R or find because they get a list of files/directories before any names were changed. If a directory name was changed then the file inside would no longer have the path specified by the ls -R or find and mv wouldn't be able to find the original file to be renamed.
So what I came up with was a check to see if there are more directories inside the specified one and run the scipt again for each one of those directories.
The only problem I am having is that I can't for the life of me figure out how to check if a directory exists (hence the commented out part). What I have at the moment works, but throws errors if there aren't any nested directories (as in can't find */) but it doesn't stop the rest from working.
Thanks for the help
The Kooman
09-26-2001, 11:10 PM
The only problem I am having is that I can't for the life of me figure out how to check if a directory exists (hence the commented out part). What I have at the moment works, but throws errors if there aren't any nested directories (as in can't find */) but it doesn't stop the rest from working.[/QB]
Do a check on the return status of the "ls */":
if ls -d */ &> /dev/null
then
listOfDirectories="`ls -d $directory*/`"
else
echo "No subdirectories"
# .... do what has to be done
fi
# proceed ...
HTH
Silent Bob
09-27-2001, 04:44 PM
Thanks The Kooman,
That's just what I was looking for (I'll admit that I didn't know you could check the return status of commands, guess that marks me out as a newbie again :))