3. huhtikuu 2011, 10:42

Symlinkit oikeiksi tiedostoiksi: parantelua

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

Tageja: , ,

---
---

---

Aiheen vierestä