Help needed with BASH scripts!

Recommended Videos

Playbahnosh

New member
Dec 12, 2007
606
0
0
Hello Escapians!

I have some problems with BASH scripting, I'd like to ask the local UNIX gurus to help me with this. Please?

This is the one I need help with:

This is a script with one parameter (ex: dirplus.sh). It should do the following when ran:
if the parameter is not a directory, then write ERROR to the standard output. If it is, enter the directory and count every directory and file, then ask for an extension (read from standard input) for each of them (just some letter, like a, b, d, ... it doesn't have to be a real extrension), when finished with the reading, write the number of files and directories in the directory given in the parameter to std output (just the number, don't count hidden files and folders). Then take the extensions and append them to the end of each file and directory respectively (rename them and write the extension to the end of each file).

Here is an example of how it should run:

>ls -l
drwxr-xr-x 3 antiemes antiemes 4096 2008-02-08 01:02 bitumen
drwxr-xr-x 5 antiemes antiemes 4096 2008-02-08 01:02 elnyom
-rw-r--r-- 1 antiemes antiemes 966 2008-02-08 01:02 elv.txt
-rw-r--r-- 1 antiemes antiemes 856 2008-02-08 01:02 extra.txt
-rw-r--r-- 1 antiemes antiemes 1040 2008-02-08 01:02 fadora.txt
-rw-r--r-- 1 antiemes antiemes 1067 2008-02-08 01:02 fal.bin
drwxr-xr-x 3 antiemes antiemes 4096 2008-02-08 01:02 gyullad
-rw-r--r-- 1 antiemes antiemes 1041 2008-02-08 01:02 harmas.pl
drwxr-xr-x 3 antiemes antiemes 4096 2008-02-08 01:02 hazugsag
-rw-r--r-- 1 antiemes antiemes 1063 2008-02-08 01:02 szukseg.dat
-rw-r--r-- 1 antiemes antiemes 480 2008-02-08 01:02 tiszta.pas
-rw-r--r-- 1 antiemes antiemes 1014 2008-02-08 01:02 ugyetlen.so
-rw-r--r-- 1 antiemes antiemes 1462 2008-02-08 01:02 vastag.jpg

>./feladat1.sh
ERROR

>./feladat1.sh elv.txt
ERROR

>ls -l elnyom
drwxr-xr-x 2 antiemes antiemes 4096 2008-02-08 01:02 csipo
-rw-r--r-- 1 antiemes antiemes 776 2008-02-08 01:02 extra.txt
-rw-r--r-- 1 antiemes antiemes 1352 2008-02-08 01:02 fadora.txt
-rw-r--r-- 1 antiemes antiemes 1848 2008-02-08 01:02 farol.png
drwxr-xr-x 2 antiemes antiemes 4096 2008-02-08 01:02 hatvan
-rw-r--r-- 1 antiemes antiemes 889 2008-02-08 01:02 jelzo.dll
-rw-r--r-- 1 antiemes antiemes 1090 2008-02-08 01:02 kepes.bin
-rw-r--r-- 1 antiemes antiemes 2079 2008-02-08 01:02 kez.mpeg
drwxr-xr-x 4 antiemes antiemes 4096 2008-02-08 01:02 szukseg
-rw-r--r-- 1 antiemes antiemes 1940 2008-02-08 01:02 tobbi.dat

>./feladat1.sh elnyom
a
b
c
d
e
f
g
h
i
j
10

>ls -l elnyom
total 40
drwxr-xr-x 2 antiemes antiemes 4096 2008-02-08 01:02 csipoa
-rw-r--r-- 1 antiemes antiemes 776 2008-02-08 01:02 extra.txtb
-rw-r--r-- 1 antiemes antiemes 1352 2008-02-08 01:02 fadora.txtc
-rw-r--r-- 1 antiemes antiemes 1848 2008-02-08 01:02 farol.pngd
drwxr-xr-x 2 antiemes antiemes 4096 2008-02-08 01:02 hatvane
-rw-r--r-- 1 antiemes antiemes 889 2008-02-08 01:02 jelzo.dllf
-rw-r--r-- 1 antiemes antiemes 1090 2008-02-08 01:02 kepes.bing
-rw-r--r-- 1 antiemes antiemes 2079 2008-02-08 01:02 kez.mpegh
drwxr-xr-x 4 antiemes antiemes 4096 2008-02-08 01:02 szuksegi
-rw-r--r-- 1 antiemes antiemes 1940 2008-02-08 01:02 tobbi.datj
I know it's not a very complicated script, but I'm stuck at trying to decode it from the output. Please help?
 

Gitsnik

New member
May 13, 2008
798
0
0
I think you have your decoding wrong. But maybe not. Anyway, I just wrote this in a text pad without checking it, it should give you a simple syntax setup though:

Code:
PARAM=$1
if [ -d $PARAM ];
then
	cd "$PARAM";
	TOTAL=`find . | wc -l`
	echo -n "Extension: "
	read EXTENSION;
	# You have one extension in variable EXTENSION
	find . -type f -exec mv {} {}$EXTENSION \;
else
	echo "ERROR"
fi
Edit: I'm fairly certain this won't work, in fact I would say that second "find" is a dead-wrong command. Then again this sounds like homework, and I refuse to do that point blank for you.

Edit 2: If you want to append extensions in alphabetical order you'd want to set up some sort of list and do a loop over them, you can do nifty things like "find . -type f | while read FILE; do mv $FILE $FILE$CURRENTLETTER; done" if you want to.
 

Playbahnosh

New member
Dec 12, 2007
606
0
0
Actually, it is homework, but I have four scripts to be done, this is just one of them. I'm not an asshole to make you do my homework, that's why I asked for this single one only, so I could have a script to start out from and be able to do the rest of the 4 on my own, to understand this whole scripting stuff.

I can see where you are gettin at with that script, but I don't understand that 'find' line at all. And what is that '-d' stuff in the 'if' branch with $PARAM? :S

EDIT: don't have to append them in alphabetial order, it's just a sample run of the script, it could be anything to append there.
 

Gitsnik

New member
May 13, 2008
798
0
0
Playbahnosh said:
Actually, it is homework, but I have four scripts to be done, this is just one of them. I'm not an asshole to make you do my homework, that's why I asked for this single one only, so I could have a script to start out from and be able to do the rest of the 4 on my own, to understand this whole scripting stuff.

I can see where you are gettin at with that script, but I don't understand that 'find' line at all. And what is that '-d' stuff in the 'if' branch with $PARAM? :S

EDIT: don't have to append them in alphabetial order, it's just a sample run of the script, it could be anything to append there.
The '-d' is checking if it is a directory, you'll find a lot of helpful stuff online but I heartily recommend the IBM stuff:

http://www.ibm.com/developerworks/library/l-bash3.html

find is also a nifty command to learn and love, "man find" isn't that useful but you should read it first (once you get a feel for these things they become easier to read). Basically what I said was "find in dir ." in that first one, then counted the lines out with wc -l, the second one was a little more complex but did "find in dir (current dir is the single dot) where type is file" the exec part was execute a program, but I'm fairly certain it is wrong.

I didn't mean to sound narky re the homework thing, guess I spend too much time on perlmonks :D

Edit: Oh yeah bash is a bit funny with variable assignment:

PARAM=$1

assigns param is the first argument to the script, but you can't then reference it as PARAM again, you have to reference it as $PARAM otherwise you will (potentially) overwrite the variable. Hold tight and I'll PM you a complex script I use to find files in a 1TB volume.
 

Playbahnosh

New member
Dec 12, 2007
606
0
0
Gitsnik said:
Playbahnosh said:
Actually, it is homework, but I have four scripts to be done, this is just one of them. I'm not an asshole to make you do my homework, that's why I asked for this single one only, so I could have a script to start out from and be able to do the rest of the 4 on my own, to understand this whole scripting stuff.

I can see where you are gettin at with that script, but I don't understand that 'find' line at all. And what is that '-d' stuff in the 'if' branch with $PARAM? :S

EDIT: don't have to append them in alphabetial order, it's just a sample run of the script, it could be anything to append there.
The '-d' is checking if it is a directory, you'll find a lot of helpful stuff online but I heartily recommend the IBM stuff:

http://www.ibm.com/developerworks/library/l-bash3.html

find is also a nifty command to learn and love, "man find" isn't that useful but you should read it first (once you get a feel for these things they become easier to read). Basically what I said was "find in dir ." in that first one, then counted the lines out with wc -l, the second one was a little more complex but did "find in dir (current dir is the single dot) where type is file" the exec part was execute a program, but I'm fairly certain it is wrong.

I didn't mean to sound narky re the homework thing, guess I spend too much time on perlmonks :D

Edit: Oh yeah bash is a bit funny with variable assignment:

PARAM=$1

assigns param is the first argument to the script, but you can't then reference it as PARAM again, you have to reference it as $PARAM otherwise you will (potentially) overwrite the variable. Hold tight and I'll PM you a complex script I use to find files in a 1TB volume.
Awesome! Thanks for the help!
Well, I do know the 'man' command, but that does not help me in most cases, because it doesn't cite examples in context and usage. It only tells what that single command is doing in short, nothing really useful. But the example is welcome. I learn more from example scripts and stuff like that, at least that's what I noticed. Thanks again!
 

Playbahnosh

New member
Dec 12, 2007
606
0
0
Gitsnik said:
PARAM=$1
if [ -d $PARAM ];
then
cd "$PARAM";
TOTAL=`find . | wc -l`
echo -n "Extension: "
read EXTENSION;
# You have one extension in variable EXTENSION
find . -type f -exec mv {} {}$EXTENSION \;
else
echo "ERROR"
fi

Edit: I'm fairly certain this won't work, in fact I would say that second "find" is a dead-wrong command.
Okay, I got my own script "sprout" now :) It doesn't look like much, but it does do it's job

#!/bin/bash

if [ -z $1 ]
then
echo "ERROR"
exit

elif [ ! -d $1 ]
then
echo "ERROR"
exit
fi
cd $1
ls
echo "gimme a file:"
read FIL
if [ -f $FIL ]
then
echo "extension: "
read KIT
mv $FIL $FIL$KIT
else
echo "argument not a file"
exit
fi
It does the first part, it examines the argument if it's empty or it's not a directory, and if either of that is true, it exits with error message. Then it enters the directory and asks for a file (again examining the input) and then it asks for an extension then appends it to the end of the file.

So what I need help with now: how can I run the script on ALL files and subfolders in a directory, so it asks for an extension for each of them (without asking for a file from std input every time) and renames them accordingly? I tried to use loops (for, do) but I cannot seem to do it (error: too many arguments, when I try to give $FIL the entire ls command like FIL = $(ls) it doesn't work)

Please? :(
 

Gitsnik

New member
May 13, 2008
798
0
0
Playbahnosh said:
It does the first part, it examines the argument if it's empty or it's not a directory, and if either of that is true, it exits with error message. Then it enters the directory and asks for a file (again examining the input) and then it asks for an extension then appends it to the end of the file.

So what I need help with now: how can I run the script on ALL files and subfolders in a directory, so it asks for an extension for each of them (without asking for a file from std input every time) and renames them accordingly? I tried to use loops (for, do) but I cannot seem to do it (error: too many arguments, when I try to give $FIL the entire ls command like FIL = $(ls) it doesn't work)

Please? :(
I gave you the hint for that earlier :)

Code:
find . -type f | while read $FIL; do echo -n "extension: "; read $KIT; mv $FIL $FIL$KIT; done
You can remove the whole if [ -f $FIL ] statement (if/else/fi) and replace it with something like that. Again, that is untested and written from memory.

While is reading line by line the output from find, which if you type it in a directory looks something like:

Code:
./rdiff-backup-data/session_statistics.2009-03-20T22:00:02+10:30.data
./rdiff-backup-data/session_statistics.2009-03-21T12:00:02+10:30.data
./rdiff-backup-data/session_statistics.2009-03-21T16:00:02+10:30.data
./rdiff-backup-data/session_statistics.2009-03-21T22:00:01+10:30.data
./rdiff-backup-data/session_statistics.2009-03-22T12:00:01+10:30.data
./rdiff-backup-data/session_statistics.2009-03-22T16:00:02+10:30.data
./rdiff-backup-data/session_statistics.2009-03-22T22:00:00+10:30.data
./smtpproxy.pl
./smtpproxyv1.pl
./smtpproxyv2.pl
./smtpproxyv3.pl
./traceroute
./words3.txt
./zarchive.sh
That was generated by typing "find . -type f" in the directory I was working in at the time (my backup directory incidentally).

Good job on getting this far.
 

Playbahnosh

New member
Dec 12, 2007
606
0
0
Gitsnik said:
Playbahnosh said:
It does the first part, it examines the argument if it's empty or it's not a directory, and if either of that is true, it exits with error message. Then it enters the directory and asks for a file (again examining the input) and then it asks for an extension then appends it to the end of the file.

So what I need help with now: how can I run the script on ALL files and subfolders in a directory, so it asks for an extension for each of them (without asking for a file from std input every time) and renames them accordingly? I tried to use loops (for, do) but I cannot seem to do it (error: too many arguments, when I try to give $FIL the entire ls command like FIL = $(ls) it doesn't work)

Please? :(
I gave you the hint for that earlier :)

Code:
find . -type f | while read $FIL; do echo -n "extension: "; read $KIT; mv $FIL $FIL$KIT; done
You can remove the whole if [ -f $FIL ] statement (if/else/fi) and replace it with something like that. Again, that is untested and written from memory.

While is reading line by line the output from find, which if you type it in a directory looks something like:

Code:
./rdiff-backup-data/session_statistics.2009-03-20T22:00:02+10:30.data
./rdiff-backup-data/session_statistics.2009-03-21T12:00:02+10:30.data
./rdiff-backup-data/session_statistics.2009-03-21T16:00:02+10:30.data
./rdiff-backup-data/session_statistics.2009-03-21T22:00:01+10:30.data
./rdiff-backup-data/session_statistics.2009-03-22T12:00:01+10:30.data
./rdiff-backup-data/session_statistics.2009-03-22T16:00:02+10:30.data
./rdiff-backup-data/session_statistics.2009-03-22T22:00:00+10:30.data
./smtpproxy.pl
./smtpproxyv1.pl
./smtpproxyv2.pl
./smtpproxyv3.pl
./traceroute
./words3.txt
./zarchive.sh
That was generated by typing "find . -type f" in the directory I was working in at the time (my backup directory incidentally).

Good job on getting this far.
Thanks, and for the help also, but I found some roadblocks with the "find" approach, such as the order that command lists files compared to "ls". It's different. If the listing order is different, then the order of the extensions won't match the specifications. And since the scripts will be validated by a robot (validation program, not people), there is only one good answer, and since it was "ls" in the example run, I rather used that instead.

I alreasy submitted my scripts, I hope they will be good. At least they do what the example suggests. Here is what I did:

#!/bin/bash

if [ -z $1 ]
then
echo "ERROR"
exit

elif [ ! -d $1 ]
then
echo "ERROR"
exit
fi
cd $1
FILES=$(ls)
NUM=$(ls | wc -l )
for X in $FILES
do
read EXT
mv $X $X$EXT
done
echo $NUM
It's rather simplistic, but it runs just like in the example, and I think it conforms with the assignment guidelines as well. Again, thanks... :)
 

Gitsnik

New member
May 13, 2008
798
0
0
Playbahnosh said:
It's rather simplistic, but it runs just like in the example, and I think it conforms with the assignment guidelines as well. Again, thanks... :)
Ah my bad for not thinking about sort-order. Well done.