LX-SCR-INFO-file-io
updated 7/27/10 00:14
file-io
Eigenlijk doen we al een hele tijd aan file i/o:
- we lezen files met while, regel per regel
- we lezen files met for, woord voor woord
Files schrijven kan je met een simpele redirect
> of
>> en dat doen we ook regel per regel met
echo, en woord voor woord met
printf.
Tenslotte zijn er nog een heleboel tools, met als belangrijkste
sed, om tekstregels en woorden in te voegen, te verwijderen, of te vervangen.
We beginnen met enkele eenvoudige voorbeelden (met dank aan Koen Lefever)
- Een file aanmaken en er naartoe schrijven
Een file openen om er naartoe te schrijven doen we met >
De file wordt dan eerst (opnieuw) geïnitialiseerd. En dan met karakters, en layout elementen (cr, lf, tab, space) volgeschreven.
Volgende tekstregels voegen we toe met >>
In het volgende voorbeeld schrijven we een script "maaktext" dat een bestand "tekstje" aanmaakt met daarin de volgende regels:
Dit is de eerste regel
Dit is de tweede regel
Dit is regel drie
Dit is de laatste regel
#!/bin/bash
#
# maaktext: maakt het bestand tekstje
#
echo "Dit is de eerste regel" > tekstje
echo "Dit is de tweede regel" >> tekstje
echo "Dit is regel drie" >> tekstje
echo "Dit is de laatste regel">> tekstje
exit 0
De output is als volgt:
$ maaktext
$ ls -l tekstje
-rw-r--r-- 1 koen users 88 2010-07-25 18:38 tekstje
$ cat tekstje
Dit is de eerste regel
Dit is de tweede regel
Dit is regel drie
Dit is de laatste regel
- more fun: parameter shift, exit status, tee
In het volgende voorbeeld "uhavbenhckd" schrijven we in de home directories van alle gebruikers die als argument achter de naam van dit script worden ingetikt. We lezen dus één voor één alle parameters. Dat doen we op een iets andere manier dan we zouden verwachten. Het shift commando verplaatst parameters naar links ($2 komt in $1 terecht, $3 in $2, enzoverder)
Bovendien controleren we de exit status van onze schrijfopdracht. De exit status wordt opgevraagd met $? Indien $? nul is, is alles goed verlopen, maar indien niet nul, is er een error opgetreden.
We plaatsen dan een file op de Desktop van de slachtoffers, met als naam "DEFACED" en als inhoud "U h4v3 b33n h4x0red!!!"
#!/bin/bash
#
# uhavbenhckd: voegt een bestand toe op de desktop
# van de users in $1 en volgende
#
function timestamp {
echo $(date +"%Y%m%d%H%M%S")
}
logfile=hacked.log
echo $(timestamp)\: -------------------------------------------- >> $logfile
echo $(timestamp)\: $0 was initiated ... >> $logfile
while [ $# -gt 0 ] # zolang er nog argumenten zijn ...
do
# zijn uitroeptekens speciale tekens -> \!\!\!
# we willen de error messages sturen naar de logfile, daarom haakjes
( echo "U h4v3 b33n h4x0red\!\!\!" > /home/$1/Desktop/DEFACED ) 2>> $logfile
# nu testen we de exit status
if [ "$?" -eq "0" ]
# tee brengt output op scherm en in de file, tee -a doet een append
then echo $(timestamp)\: user $1 was hacked succesfully | tee -a $logfile
else echo $(timestamp)\: user $1 was protected by darth vadar | tee -a $logfile
fi
# en nu schuiven we de parameters op naar links
shift
done
output:
$ uhavbenhckd geert koen bert root
20100725234118: user geert was protected by darth vadar
20100725234118: user koen was protected by darth vadar
20100725234118: user bert was hacked succesfully
20100725234118: user root was protected by darth vadar
$ cat hacked.log
20100725234118: --------------------------------------------
20100725234118: /home/bert/bin/uhavbenhckd was initiated
/home/bert/bin/uhavbenhckd: line 14: /home/geert/Desktop/DEFACED: No such file or directory
20100725234118: user geert was protected by darth vadar
/home/bert/bin/uhavbenhckd: line 14: /home/koen/Desktop/DEFACED: No such file or directory
20100725234118: user koen was protected by darth vadar
20100725234118: user bert was hacked succesfully
/home/bert/bin/uhavbenhckd: line 14: /home/root/Desktop/DEFACED: No such file or directory
20100725234118: user root was protected by darth vadar
$ ls ../Desktop
6_grafische_schermen_op_SuSE
802-lan-standards
Bruce_Perens
DEFACED
dell_lat505
$ cat ../Desktop/DEFACED
U h4v3 b33n h4x0red\!\!\!
Er is toch iets misgegaan met die uitroeptekens !!!
- oefeningen
- Schrijf een script met als naam "addprofile" dat je .profile opent en er de volgende regels aan toe voegt:
export PATH=$PATH:~/bin
alias cls="clear"
alias ll="ls -al"
De quotes moeten er ook in op één of andere manier ...
- Schrijf een script met als naam "creagebr" dat een reeks gebruikersnamen verwacht als argumenten en deze gebruikers dan aanmaakt. Geef ze het paswoord "sdf12345". Test de exit status van het commando useradd. Schrijf per aangemaakte gebruiker in een logbestand /var/log/creagebr dat die gebruiker toegevoegd is, en per fout dat er een fout is opgetreden. Stuur dezelfde output op scherm.
- files lezen
Files lezen doen we al een tijdje met while. Toch nog een voorbeeld:
We schrijven een script "numberline" dat een bestandsnaam krijgt als argument (en een bestandsnaam vraagt als er geen argument gegeven wordt). Het bestand wordt met regelnummers afgedrukt.
#!/bin/bash
#
# numberline: drukt regelnummers af voor tekstregels van een bestand
#
if [ $# -eq 0 ]
then
read -p "Bestandsnaam: " filenaam
else
filenaam=$1
fi
teller=0
while read lijn
do
(( teller++)) # teller = teller + 1 (bash wiskunde lijkt op C)
echo "$teller: $lijn"
done < $filenaam
exit 0
$ numberline tekstje
1: Dit is de eerste regel
2: Dit is de tweede regel
3: Dit is regel drie
4: Dit is de laatste regel
Maar het volgende 1-regel-script werkt ook (nu ja, bijna ... :-)
#!/usr/bin/nl
# nummerlijn: drukt regelnummers af voor tekstregels van een bestand
$ nummerlijn tekstje
1 #!/usr/bin/nl
2 Dit is de eerste regel
3 Dit is de tweede regel
4 Dit is regel drie
5 Dit is de laatste regel
Maar we hebben eigenlijk helemaal geen script nodig:
$ nl tekstje
1 Dit is de eerste regel
2 Dit is de tweede regel
3 Dit is regel drie
4 Dit is de laatste regel
- oefeningen
- Schrijf een script met als naam "achterstevoren" dat een bestand regel per regel inleest in een array en vervolgens achterstevoren afdrukt.
- Schrijf een script met als naam "tmpback" dat een pad naar een folder vraagt en dan een tar-backup van die folder in /tmp zet. De backup is een tar.gz file van de ingegeven folder. De tar.gz filenaam is hetzelfde als de pathnaam, waarbij slashes zijn vervangen door underscores. Redirect de output van tar naar een logbestand met als naam tmpback.log
- exec ...
Soms is het nodig verschillende files tegelijkertijd te lezen. Je kan dan een fd-nummer (file descriptor) aan een file geven (een integer groter dan 5) en werken met de volgende syntax:
#Open file $1 for reading to SHARE_LINE
exec 10<$configfile
#initialize counter
count=0
#read file line per line in SHARE_LINE
while read LINE <&10; do
SHARE_LINE[$count]=$LINE
((count++))
done
echo 'Number of elements in sharedefinition file:' ${#SHARE_LINE[@]}
echo
#Close file
exec 10>&-
Meer over exec vind je op de volgende links:
http://www.linuxjournal.com/content/reading-multiple-files-bash
http://www.linuxtopia.org/online_books/advanced_bash_scripting_guide/x13082.html