ubuntuusers.de

Confdatei an Shell Script mit und ohne Parameter übergeben

Status: Gelöst | Ubuntu-Version: Ubuntu 16.04 (Xenial Xerus)
Antworten |

Leubi

Avatar von Leubi

Anmeldungsdatum:
23. April 2017

Beiträge: 36

Guten Morgen, ich stehe mal wieder auf den Schlauch...

Ich möchte einem Script eine Confdatei übergeben in zwei verschiedene Möglichkeiten.

Die 1. Möglichkeit soll sein das ich das Script test.sh einfach ohne Parameter ausführe. Die Confdatei ist dann im selben Verzeichnis wie das Script.

#!/bin/sh
#
FILE="./test.conf"
. $FILE
echo $Variable1
echo $Variable2
echo $Variable2 > $PfadSpeicher$NameSpeicher

Soweit geht es auch.

Die 2. Möglichkeit sollte so sein das ich das Script mit z.B. test.sh -C /pfadzurconfdatei/test.conf ausführe. Und da komme ich nicht weiter. Mein Ansatz war mit case aber die Idee ist glaube ich nicht sehr elegant und gut ☹

#!/bin/sh
#
case "$1" in
        -C)

. $FILE
echo $Variable1
echo $Variable2
echo $Variable2 > $PfadSpeicher$NameSpeicher
exit 1
        ;;
       *)
         FILE="./test.conf"
. $FILE
echo $Variable1
echo $Variable2
echo $Variable2 > $PfadSpeicher$NameSpeicher
exit 1
esac
else

Eventuell hat ja jemand eine andere Idee wie ich das machen könnte.

LG Leubi

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4695

Wohnort: Berlin

@Leubi: Schau Dir mal Bash's eingebautes getopts an, oder alternativ das getopt-Programm. Für einfache Optionen kann man sich das allerdings tatsächlich mit while, case, und shift selbst nachbasteln. Das hast Du ja schon fast.

greenmoon

Anmeldungsdatum:
10. März 2010

Beiträge: 269

ich würde mir eine Variabel definieren mit default Wert aktuelles Verzeichnis. Wenn ein anderes Verzeichnis als Parameter übergeben wird setze die Variable auf das Verzeichnis. Gelesen wird dann immer Verzeichnis/config. Das kannst du dann mit getopt umsetzen.

Leubi

(Themenstarter)
Avatar von Leubi

Anmeldungsdatum:
23. April 2017

Beiträge: 36

Grüße, die Varieante mit case wäre nicht so schön da ich die Daten im Script immer doppelt habe.

Mit getops bekomme ich das nicht hin ☹ das mit dem Platzhalter ist irgend wie verzwickt.

Im Moment bekomme ich garnichts hin weder wenn ich einfach nur test.sh mache und schon garnicht test.sh -C /pfadzurconf/test.conf.

Mal schauen wie es lösen kann.

lg Stefan

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4695

Wohnort: Berlin

@Leubi: Was meinst Du mit „Daten im Script immer doppelt“? Und wo liegt das Problem bei getopts? Welcher Platzhalter? Zeig doch mal konkreten Code an dem man Dein(e) Problem(e) nachvollziehen kann.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13219

Wenn Du nichts anderes übergibst als den Namen der Konfigurationsdatei ist es ganz einfach:

1
2
3
4
5
#!/bin/sh

conf="${1:-$(dirname "$0")/test.conf}"

echo "lese $conf ..."

Sieht dann so aus

1
2
3
4
5
6
7
8
$ ./x
lese ./test.conf ...
$ $PWD/x
lese /tmp/abc/test.conf ...
$ ./x foo
lese foo ...
$ ./x /tmp/bar
lese /tmp/bar ...

Wenn Du es mit einer Option machen willst, dann via getopts:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/bin/sh

conf="$(dirname "$0")/test.conf"

while getopts C: opt; do
  case "$opt" in
  C)	conf="$OPTARG";;
  \?)	exit 1;;
  esac
done

shift $((OPTIND - 1))

echo "lese $conf ..."

Leubi

(Themenstarter)
Avatar von Leubi

Anmeldungsdatum:
23. April 2017

Beiträge: 36

Grüße,

das war mein erster Versuch mit getopts.

#!/bin/sh
#
while getopts *:C:h opts; do
        case ${opts} in
                *) var1=${FILE="./test.conf"} ;;
                C) var2=${OPTARG} ;;
                h) show_help ;;
        esac
done
. $FILE
. $var2
echo $Variable1
echo $Variable2
echo $Variable2 > $PfadSpeicher$NameSpeicher

weiter komme ich leider in Moment nicht.

Was ich mit doppelt meinte ist, wenn ich das mit case mache muß ich ja in jedem Abschnit alles das eintragen was abgearbeitet werden soll, somit wären die Einträge ja doppelt.

#!/bin/sh
#
case "$1" in
        -C)

. $FILE
echo $Variable1
echo $Variable2
echo $Variable2 > $PfadSpeicher$NameSpeicher
exit 1
        ;;
       *)
         FILE="./test.conf"
. $FILE
echo $Variable1
echo $Variable2
echo $Variable2 > $PfadSpeicher$NameSpeicher
exit 1
esac
else

Und wie über gebe ich dem Script den Pfad von der Confdatei? Wird das mit read gemacht oder gibt es da eine einfache lösung?

lg Stefan

Leubi

(Themenstarter)
Avatar von Leubi

Anmeldungsdatum:
23. April 2017

Beiträge: 36

rklm ich danke Dir.

Das ich immer --C eingeben das ist so richtig? Oder kann man das ändern das ich nur -C eingeben muss.

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13219

Leubi schrieb:

while getopts *:C:h opts; do
        case ${opts} in
                *) var1=${FILE="./test.conf"} ;;
                C) var2=${OPTARG} ;;
                h) show_help ;;
        esac
done

Das mit dem Stern funktioniert nicht so, wie Du denkst. Lass das einfach weg.

Und wie über gebe ich dem Script den Pfad von der Confdatei? Wird das mit read gemacht oder gibt es da eine einfache lösung?

Wir reden doch gerade die ganze Zeit darüber, wie man das macht. Ich verstehe die Frage nicht.

Leubi schrieb:

Das ich immer --C eingeben das ist so richtig?

Nein. Beim Aufruf gibst Du "-C dateiname" an. Du müsstest auch einen Fehler sehen, wenn Du das mal mit meinem Skript ausprobierst.

Oder kann man das ändern das ich nur -C eingeben muss.

Mit getopts gibst Du immer nur einen Gedankenstrich ein. Zwei sind normalerweise für Optionen mit langen (mehr als ein Zeichen) Namen reserviert.

Leubi

(Themenstarter)
Avatar von Leubi

Anmeldungsdatum:
23. April 2017

Beiträge: 36

So jetzt geht es doch hatte mal wieder einen Gedanckenfehler ... bin halt keine 40 mehr 😉

Könnt man es so ändern wenn man z.b. -a oder -b oder irgend etwas anderes wie z.B. nur den pfad angibt das da eine Fehlermeldung kommt?

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4695

Wohnort: Berlin

@Leubi: Also wenn Du eine Option angibst die es nicht gibt, dann kommt bereits ein Fehler:

bj@god:~$ ./test.sh -a x
./test.sh: illegal option -- a 

Und wenn Du keine Positionsargumente haben möchtest, dann müsstest Du halt nach dem shift das am Ende der Argumentauswertung steht, halt prüfen, ob noch Argumente da sind, und falls ja, das Programm mit einer entsprechenden Meldung abbrechen.

Leubi

(Themenstarter)
Avatar von Leubi

Anmeldungsdatum:
23. April 2017

Beiträge: 36

Grüße, so ich bedanke mich bei Euch beide. Jetzt geht es so wie ich es mir Vorgestellt hatte.

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4695

Wohnort: Berlin

Mit Prüfung ob am Ende keine Positionsargumente mehr da sind:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/bin/bash
readonly SCRIPT_NAME=$(basename "$0")

CONFIG_FILE="$(dirname "$0")/test.conf"

while getopts 'C:' option; do
    case $option in
        C) CONFIG_FILE=$OPTARG;;
        ?) exit 1;;
    esac
done
shift $((OPTIND - 1))

if (( $# )); then
    echo "$SCRIPT_NAME: unexpected argument(s): $*" 1>&2
    exit 1
fi

echo "Config file: $CONFIG_FILE"

rklm Team-Icon

Projektleitung

Anmeldungsdatum:
16. Oktober 2011

Beiträge: 13219

Marc_BlackJack_Rintsch schrieb: ...

Ein paar kleinliche Hinweise:

  • Für das Skript braucht man keine bash, wenn man Zeile 14 anders schreibt. Dann kommt man mit der schnelleren sh aus.

  • In Zeile 9 sollte man \? verwenden, weil sonst jeder Text mit einem Buchstaben erfasst wird! (Das ist ein Muster und keine Zeichenkette. s.u.)

  • basename kann man einfacher durch eine spezielle Parameter Expansion ersetzen.

  • Kleinschreibung von Skriptvariablen verhindert Verwechslung mit Umgebungsvariablen.

1
2
3
4
5
6
7
$ for i in a b \?; do echo "i=$i"; case "$i" in a) echo A;; \?) echo '\?';; ?) echo '?'; esac; done
i=a
A
i=b
?
i=?
\?

In Summe:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/sh

readonly script_name="${0##*/}"

config_file="$(dirname "$0")/test.conf"

while getopts 'C:' option; do
    case $option in
        C) config_file=$OPTARG;;
        \?) exit 1;;
    esac
done

shift $((OPTIND - 1))

if [ $# -gt 0 ]; then
    echo "$script_name: $# unexpected argument(s): $*" 1>&2
    exit 1
fi

echo "Config file: $config_file"

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4695

Wohnort: Berlin

@rklm: Grossschreibung mindestens von Konstanten, aber auch von globalen Variablen verhindert Verwechslung mit lokalen Namen.

“Die“ sh ist nur dann schneller wenn das nicht die bash ist. Und wenn man Pech hat ist die sh auch nicht POSIX-kompatibel oder man verwendet dann etwas was nur die dash kann, aber irgendwo anders eine sh nicht. Ich schreibe jedenfalls lieber explizit für eine konkrete Shell und verlasse mich nicht so gerne darauf was sh dann letztendlich wirklich ist.

Was immer an "${0##*/}" einfacher ist — die Lesbarkeit ist es jedenfalls nicht. Ich bleibe da lieber bei "$(basename $0)". ☺

Antworten |