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