ProgrammingThis forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I've just started having a serious look at bash scripting and have sofar found my sig to be a great resource.
I'm trying to make a substitution script to prepend a 0 to a group of audio files. So far I've come up with this:
Code:
#!/bin/bash
#
#test script to prepend a 0 to any type of file
echo "This script will prepend a 0 to any file"
echo "or group of files specified "
echo
echo "Specify path / file"
read files
for i in "$files" ; do
cp "$i" "0$i"
done
exit
cp will be replaced by mv once the script works.
The reason why I'm using double quotes around the variables is that most filenames contain spaces. However, the script will still not work on those files.
Code:
$ ~/prepend0.sh
This script will prepend a 0 to any file
or group of files specified
Specify path / file
./*ogg
cp: cannot stat `./*ogg': No such file or directory
however:
Code:
$ ls
00-Lords_and_Ladies.ogg
00 - Lords and Ladies.ogg
apparently there's a problem with the way I read the files ito the script. If I give individual file names it works fine, but what I need it to indicate a folder (and possibly an extention type) and convert all the files that correspond to the pattern.
./*.ogg will not work, nor will *.ogg or anything else I've tried.
I've found a way to use sed to extract the filenames I need:
Code:
files=`ls -l | sed 's/\([^ ]*[ ]*\)\{8\}\([.]*\)/\2/' | grep .ogg`
for i in "$files" ; do
cp "$i" "0$i"
done
exit
but this returns an error because instead of supplying individual file names to the for function it concatenates the filenames like file1.ogg/file2.ogg/file3.ogg
What am I doing wrong? Am I making things too complicated?
Hey,
Thanks for the link linmix, i'm not a member of LinuxQuestions.org. It's because you have quotes; the system is taking it literally:
you entered
./*
as $files. Because you said
cp "$files"
the quotes make the system think the ./* is literall, and a file is really called ./* and not all the files in the current dir. You should use the sed method or use a # find command to find the files, then cp them.
Firewing1
Thanks all for your help and interest. I'll study all your suggestions as I'm sure there's a lot to learn from them.
Firewing: welcome to LQ!
Won't I get in trouble if i don't use double quotes because of spaces in the filenames? I'll check anyway.
Dave I'm not sure what your script does, but I like the approach o setting 'i' as any 'jpg' file in the directory. that would enable the selection I was looking for to subsequently enter into the 'for' loop
homey I see what you mean and what I like about it is that it becomes a script with arguments. I had a look at using 'ls' myself, but that could cause a problem if there were another directory inside the one I'm trying to process. I tried coming up with a line including sed to cicumvent this problem, but it won't work yet
Code:
find -type f -maxdepth 1 -exec echo `sed 's/\(\.\/\)\(\[.\]*\)/\2/'` ';'
Originally posted by linmix
[ Dave I'm not sure what your script does, but I like the approach o setting 'i' as any 'jpg' file in the directory. that would enable the selection I was looking for to subsequently enter into the 'for' loop
It is not important what the script does. It is important that you read the answers to your question and also the scripts others have written and understand the solutions put before you. In this case you picked up on the correct part. Looks like you did not know what to call it. Its called a 'for loop', work horse of the coding world.
Quote:
Firewing: welcome to LQ!
Won't I get in trouble if i don't use double quotes because of spaces in the filenames? I'll check anyway.
I too thought this was true. Let me offer a snippet of code someone showed me that proves different.
I am reading a file with entries that take this flavor.
Firewing1 I checked on the double quotes but it makes no difference: tried "$i" $i and ${i} and everything gives me the same error messages. The problem is with the reading in of the files.
I tried sed (as included in the first post) but the sed command doesn't work properly yet as it concatenates file names instead of giving them to me 1 by 1.
Hko Thanks for your input. I've been trying to find out why you used a while loop instead of a for loop and, frankly, I don't see the difference.:0 It works though, so thanks a mil!
It's also solved a problem I had with mv because it complained the second parameter wasn't a directory + I like the idea of using a pipe: it's really compact.
Dave Way over my head ... for now However I'm determined to make sense of it all one day.
Unfortunately I only have acces to a dual-boot box with no internet access on the linux side so it's a little complicated to check everything immediately. I will though
I've started reading the Advanced Scripting Guide . Section 2.2 is titled 'Preliminary Exercises' and states:
"Write a script that upon invocation shows the time and date, lists all logged-in users, and gives the system uptime. The script then saves this information to a logfile."
which works fine, BUT, I only send the info to a file and don't show it in the terminal. After reading about redirection of stout I haven't found a way to both display and redirect. Any ideas?
I'm sorry, don't follow you, but I'll show you the code:
Well, this is the problem with BASH. it can't tell the diff between literal and unliteral things, which is why PHP is the language of my choice. I ususally let users enter either a complete path or ./*, and PHP will add the backslashes where needed. So, i can do
cp $file 0${file}
and not worry about spaces, cause PHP adds backslashed before spaces with a function i invented.
But, if you REALLY want to do it in bash, then you'll either
1) Use # zenity --file-selection --separator=";" and make BASH consider after each ; a new file
(this makes literal paths) OR,
2) make it non-literal (no quotes on variables) but echo a warning saying to the user to backslash ( \ ) spaces, and any other special character:
#!/bin/bash
echo "Please execute 'prepend --usage' for correct usage, if you haven't checked already."
for arg;do
if [ "$arg" == "--usage" ]
then
echo "WARNING: Please backshash ( \ ) any space in the filename or before any special character.
EG: '/home/admin/space file', when you type the path, becomes '/home/admin/space\ file'.
You can enter multiple file by seperating them with a space."
exit
fi
if [ "$arg" == "--help" ]
then
echo "WARNING: Please backshash ( \ ) any space in the filename or before any special character.
EG: '/home/admin/space file', when you type the path, becomes '/home/admin/space\ file'.
You can enter multiple file by seperating them with a space."
exit
fi
cp $arg $(find $arg -printf %h)/$(basename $arg)0
done
if [ "$1" = "" ]
then
file=
echo -n "File : ";read file
cp $file $(find $file -printf %h)/$(basename $file)0
fi
This will
1) If --usage or --help is used, show help message and exit
2) If there's args, (commandname arg1 arg2 arg3) then copy those and exit.
3) if --usage/--help is not specified, and not paths are specified as args, promp user to enter path.
Firewing1
Originally posted by Firewing1 I'm sorry, don't follow you,
Firewing1
I simply can't get my head around files="$files $(find $i)" Don't see where it comes into the script and where it gets its input from. So files is the same as itself plus + the output of "find $i". But has i been declared before then? In that case what does find look for?.
Anyway, I have saved your reply to read it again as soon as I'm back in linux. It's a pain booting back and forth to be able to connect and then check, but it can't be helped for now. Glad I can use a computer at all (I have strict doctors orders not to move for a week!! so I'll have to make do with a borrowed laptop)
I liked the simplicity of Hko's sollution best so that's the first thing I tried. It works nicely, but only if you're in the same directory the files are in. homey's sollution however allows me to run th script from anywhere I want with a commandline option to indicate the location of the files + an error message. I liked the idea so I have tried to expand on it.
While reading about bash scripting in RUTE (see my sig.) I found the 'case' argument used to implement options so I have extended the script to include these. For the moment the -r and -a options are not very useful because they add or remove part of the end of the filename without taking into account possible extentions.
Another problem I'm working on is the fact that the script treats files and directories alike, so if there's a directory in the path idicated to the script its name will also be changed. I don't want that to happen so I'm looking at a way to change
Code:
ls $dir | while read i ; do
to something along the lines of:
Code:
ls $dir | grep ^- | \
sed -e 's/<input>/<output>'/| \
while read i ; do
but I'm still battling with this. So far
Code:
sed 's/^\([^ ]*[ ]*\){8}\([^ ]\)/\2/'
looks like it should work, but gives me no results
For now the script looks like this:
Code:
#!/bin/bash
#Example: ./test /home/images
usage()
{
echo "Usage: $0 [OPTION]... DIRECTORY"
echo " -a|--append <symbols> add <symbols> to the"
echo " end of the filename"
echo " -h|--help print this message"
echo " -p|--prepend <symbols> add <symbols> to the"
echo " beginning of the filename"
echo " -r|--remove <symbols> remove <symbols> from the"
echo " beginning of the filename"
echo " -s|--shorten <symbols> remove <symbols> from the"
echo " end of the filename"
exit 2;
}
case $1 in
-h|--help)
usage
exit 0
;;
-a|--append)
test -d "$3" || usage
app="$2"
dir="$3"
ls $dir | while read i ; do
j=`echo "$i$app"`
mv -v "$dir/$i" "$dir/$j"
done
exit 0
;;
-p|--prepend)
test -d "$3" || usage
app="$2"
dir="$3"
ls $dir | while read i ; do
j=`echo "$app$i"`
mv -v "$dir/$i" "$dir/$j"
done
exit 0
;;
-r|--remove)
test -d "$3" || usage
app="$2"
dir="$3"
ls $dir | while read i ; do
j=`echo "${i##$app}"`
mv -v "$dir/$i" "$dir/$j"
done
exit 0
;;
-s|--shorten)
test -d "$3" || usage
app="$2"
dir="$3"
ls $dir | while read i ; do
j=`echo "${i%%$app}"`
mv -v "$dir/$i" "$dir/$j"
done
exit 0
;;
-*)
echo "No such option $1"
;;
esac
usage
${i%%$app} and ${i##$app} are supposed to admit wildcards, but if I allow for this option I should also find a way to allow wildcards using the -a and -p options.
... and I'll have to come up with a sligtly better name for it
I've been trying a lot of different options with sed, but all with no result. Since I couldn't find what was going wrong I went back to my book (as per sig.) and studied the examples. Still didn't see what was wrong.
Then I tried the examples out in a vt by cutting and pasting (no typos supposedly) and still got no results!!
Due to copyright reasons I do not want to quote too much, but the example given was this:
Quote:
Now test to see what happens when you run this:
Code:
sed -e 's/\(<[^ ]*>\)\([ ]*\)\(<[^ ]*>\)/\3\2\1/g'
GNU Linux is cool
Linux GNU cool is
My terminal doesn't return the words in inverse order. So either my terminal has abnormal behaviour, or something is wrong with the command. The strange thing is that none of the sed commands given in the book work for me, which is, to say the least, suspicious.
Can anyone tell me if the sed command works for them?
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.