Steuern Sie ein Bash-Skript mit Variablen aus einer externen Datei

7

Ich möchte ein Bash-Skript wie folgt steuern:

#!/bin/sh
USER1=_parsefromfile_
HOST1=_parsefromfile_
PW1=_parsefromfile_
USER2=_parsefromfile_
HOST2=_parsefromfile_
PW2=_parsefromfile_

imapsync \
--buffersize 8192000 --nosyncacls --subscribe --syncinternaldates --IgnoreSizeErrors \
--host1 $HOST1 --user1 $USER1 --password1 $PW1 --ssl1 --port1 993 --noauthmd5 \
--host2 $HOST2 --user2 $USER2 --password2 $PW2 --ssl2 --port2 993 --noauthmd5 --allowsizemismatch

mit Parametern aus einer Steuerdatei wie folgt:

host1 user1 password1 host2 user2 password2
anotherhost1 anotheruser1 anotherpassword1 anotherhost2 anotheruser2 anotherpassword2 

Dabei steht jede Zeile für einen Skriptlauf, wobei die Parameter extrahiert und in Variablen umgewandelt werden.

Was wäre der eleganteste Weg, dies zu tun?

KLOPFEN

Perler
quelle

Antworten:

8

Bei Shell-Skripten wird dies normalerweise mithilfe der sourceFunktion erreicht, die die Datei als Shell-Skript ausführt, als ob sie in das von Ihnen ausgeführte Skript eingebunden wäre. Dies bedeutet, dass alle in der Datei festgelegten Variablen in Ihr Skript exportiert werden.

Der Nachteil ist, dass (a) Ihre Konfigurationsdatei ausgeführt wird, sodass ein Sicherheitsrisiko besteht, wenn nicht privilegierte Benutzer privilegierte Konfigurationsdateien bearbeiten können. Und (b) Ihre Konfigurationsdateisyntax ist auf eine gültige Bash-Syntax beschränkt. Trotzdem ist es wirklich praktisch.

config.conf

USER=joe
PASS=hello
SERVER=127.0.0.2

script.sh

#!/bin/bash

# Set defaults   
USER=`whoami`

# Load config values
source config.conf

foobar2000 --user=$USER --pass=$PASS --HOST=$HOST

sourcekann mit einem einzigen abgekürzt werden .- daher sind die folgenden zwei gleichwertig:

 source file.sh
 . file.sh
tylerl
quelle
1
Ich könnte mich irren, aber ich glaube, er möchte Optionen in einer Konfigurationsdatei durchlaufen. Ich weiß nicht, dass nur die Verwendung der Quelle das tut, was er will.
Zoredache
Ja, ich dachte sourceauch daran, aber ich denke, er will es nicht so.
weeheavy
Richtig, der Loop-Teil ist der wichtige, da ich einige Sachen
massenimportieren muss
3

Etwas wie das. Das wichtige Bit ist das Lesen , um eine Zeile als Array zu erfassen.

#!/bin/bash
configfile=/pathtocontrolfile
cat $configfile | while read -a HR ; do

  [[ -z ${HR[0]} ]] && continue  # skip empty lines

  USER1=${HR[0]}
  HOST1=${HR[1]}
  PW1=${HR[2]}
  USER2=${HR[3]}
  HOST2=${HR[4]}
  PW2=${HR[5]}

  imapsync \
  --buffersize 8192000 --nosyncacls --subscribe --syncinternaldates --IgnoreSizeErrors \
  --host1 $HOST1 --user1 $USER1 --password1 $PW1 --ssl1 --port1 993 --noauthmd5 \
  --host2 $HOST2 --user2 $USER2 --password2 $PW2 --ssl2 --port2 993 --noauthmd5 --allowsizemismatch

done
Zoredache
quelle
1
+1, damit ich den Unterschied zwischen [und nachschaue [[. ( tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS, wenn das OP interessiert ist.) Sehr nützlich.
SmallClanger
2
Sie können direkt in die Variablen einlesen : read -r USER1 HOST1 PW1 .... Beachten Sie, dass dies -rfast immer verwendet werden sollte (es ermöglicht das wörtliche Lesen von Backslashes). Durch whiledas Einleiten in wird eine Unterschale erstellt (was hier möglicherweise kein Problem darstellt). Sie können dies vermeiden, indem Sie die Datei in Folgendes umleiten done: done < "$configfile". @SmallClanger: Siehe auch BashFAQ / 031 .
Bis auf weiteres angehalten.
@ Tennis Williamson, natürlich hast du recht, aber das Obige war das, was ich bereits in einem Arbeitsskript hatte, bitte entschuldige die leichte Faulheit. :)
Zoredache
@ Tennis Williamson - Ah, viel klarer als das ABS. Vielen Dank. Ebenso die read -rOption.
SmallClanger
@Zoredache: Wie Dennis sagte, sollten Sie das vermeiden, cat $configfile | while ... doneindem Sie es auf verschieben, while ..... done < "$configfile"damit alle Variablen, die Sie in der while definieren oder ändern, nicht nur für die Dauer der while-Datei gelten (wenn sie sich in einer Subshell befinden), sondern auch danach existieren. Und es ist eine weniger "UUOC" (nutzlose Verwendung von Katze)
Olivier Dulac
0

Ich denke, Sie sollten so etwas wie getopts verwenden, wenn Sie Ihr Skript intelligent machen möchten, anstatt nur zu versuchen, Ihre Argumente auf Zahlenbasis zu lesen.

Etwas wie das.

#!/bin/bash

while getopts ":a" opt; do
  case $opt in
    a)
      echo "-a was triggered!" >&2
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      ;;
  esac
done


$ ./go_test.sh -a
-a was triggered!
$ 

Sie können auch Argumente analysieren. Weitere Details zum Tutorial finden Sie hier .

Napster_X
quelle
Verbesserungsbedarf: Ein robusteres Beispiel könnte sein : OPTIND=1; SILENT=":"; while getopts "${SILENT}a:bc:" opt ; do case $opt in a) val=$OPTARG; ... ;; b) ... ;; c) val=$OPTARG; ... ;; :) echo "(silent mode): -${OP TARG} needs argument"; ... ;; ?) echo "(non-silent) : option not recognized"; ... ;; esac ; done ; shift $((OPTIND - 1)) . OPTIND ist auf 1 gesetzt, sodass Sie die getopts bei Bedarf mehrmals aufrufen können, und die Verschiebung stellt sicher, dass Sie nur die verbleibenden Argumente verarbeiten. Verarbeitet standardmäßig $ 1 ... $ n, kann aber andere Argumente verarbeiten, wenn Sie sie nach dem "opt" und vor dem ";" oben
Olivier Dulac