Edellisessä jutussa hahmottelin alustavan rakennelman. Tällä kertaa se pitää parantaa loppuunsa lisäämällä argumentteja ja argumenttien hallintaa skriptiin. Kryptiset getopt-koodit aukesivat kahvin ja kokeilujen kanssa.
Minun tarvitsee tehdä vain hyvin pieniä muutoksia edelliseen versioon nähden, sillä sain haluamani toiminnallisuuden kasaan esimerkeistä. Yleinen getopt-runko ohjelmalle, joka käsittelee mielivaltaisen määrän tiedostoja:
#!/bin/bash
while getopts ":flags" flag
do
echo "$flag" $OPTIND $OPTARG
done
# after shift, $@ contains the unhandled arguments. Files etc
shift $((OPTIND-1))
for rest in "$@"; do
echo $rest
done
Taikasana on shift! Nyt jos vertaatte edellisen kirjoituksen runkoon, niin sama for-silmukka on se sielläkin. Ei muutoksia. Kokeilin tietenkin kattavasti ohjelman toimintaa noilla echo-lauseilla sun muulla. Enhän haluaisi symlink-ohjelmani aiheuttavan tietojenkadottamista.
Symlinkit siirtäen
Pari asetusta on mielessä: yksi on tietenkin mahdollisuus käyttää siirtämistä kopioinnin sijaan. Toinen ajatus on kokeiluajo. Näillähän saa jo evästä getoptille. Ensimmäinen vaihe olisi kai siirtää kovakoodaukset muuttujien taakse. Siispä ohjelman ydinosa muuttuu seuraavalla tavalla tekemällä muuttujansijoitukset:
mv "$f" "$f"_temp cp -r "$src" "$f" rm -f "$f"_temp echo -e "$GREEN""Copied" $src
Muuttuu seuraavaksi:
mv "$f" "$f"_temp $CMD "$src" "$f" rm -f "$f"_temp echo -e "$GREEN$ACT" $src
Muuttujat tietenkin esitellään ohjelman alussa oletusarvoiksi. Sitten getopt-mehua koneistoon. Ensin kopioidaan tarvittava while-silmukka ja muistetaan se shift-komento myös. Sitten on hyvä kirjoittaa kommenteiksi se summariikki halutuista argumenteista, ettei unohdu. Lopputulos näyttää tältä:
# arguments:
# -d dry run: don't actually copy
# -m move instead of copy
# -h usage
while getopts ":dmh" flag
do
case "$flag" in
d) DRYRUN=true ;;
m) CMD="mv"
ACT="Moved" ;;
h) usage ;;
esac
done
shift $((OPTIND-1))
Sisäänrakennettu getopts ottaa vastaan merkkijonon, jossa on kaikki ohjeet, joiden mukaan se parsii syötteitä. Nyt meillä ei ole mitään kummempia juttuja. Kaksoispiste alussa tarkoittaa, ettei getoptsin tarvitse antaa virhettä, jos käyttäjä antaa vääriä parametrejä. Funktio usage on tyypillinen ohjeentulostaja:
usage() {
echo "Usage: `basename $0` [options] file(s)"
echo " -d dry run: don't actually copy"
echo " -m move instead of copy"
echo " -h usage"
exit
}
# See if there is no arguments
if [ "$#" -eq "0" ] ; then
usage
fi
Kuten huomaat, meidän pitää lisäksi tehdä lisätyötä getoptsin lisäksi. Jos emme saa yhtään parametrejä niin on sama tulostaa käyttöohje.
Ja, siinäpä se oikeastaan on. Mitään muita muutoksia ei ole. Testailuissani näyttää toimivan hyvin. Lopullinen tuotos kokonaisuudessaan. Ai niin, tietysti koeajoa varten piti lisätä vähän logiikkaa silmukkaan, mutta muilta osin. Kokonainen tuotos seuraa:
#!/bin/bash
# realizes symbolic links into their flesh-and-blood counterparts
RED='\e[0;31m'
GREEN='\e[0;32m'
# defaults
CMD="cp -r"
ACT="Copied"
DRYRUN=false
usage() {
echo "Usage: `basename $0` [options] file(s)"
echo " -d dry run: don't actually copy"
echo " -m move instead of copy"
echo " -h usage"
exit
}
# See if there is no arguments
if [ "$#" -eq "0" ] ; then
usage
fi
# arguments:
# -d dry run: don't actually copy
# -m move instead of copy
# -h usage
while getopts ":dmh" flag
do
case "$flag" in
d) DRYRUN=true ;;
m) CMD="mv"
ACT="Moved" ;;
h) usage ;;
esac
done
shift $((OPTIND-1))
for f in "$@"
do
# test for symbolic
if [ -h "$f" ]; then
src=`readlink -n "$f"`
if [ ! -e "$src" ]; then
echo -e "$RED""Broken symlink: " $f
continue
fi
if $DRYRUN ; then
echo "[Dry run]" $CMD "$src" "$f"
else
mv "$f" "$f"_temp
$CMD "$src" "$f"
rm -f "$f"_temp
echo -e "$GREEN$ACT" $src
fi
fi
done