Parametry skryptu w Bash

103

Próbuję stworzyć skrypt powłoki, którego należy użyć w następujący sposób:

ocrscript.sh -from /home/kristoffer/test.png -to /home/kristoffer/test.txt

Skrypt następnie ocr skonwertuje plik obrazu na plik tekstowy. Oto, co do tej pory wymyśliłem:

#!/bin/bash
export HOME=/home/kristoffer
/usr/local/bin/abbyyocr9 -rl Swedish -if ???fromvalue??? -of ???tovalue??? 2>&1

Ale nie wiem, jak uzyskać wartości -fromi -to. Jakieś pomysły, jak to zrobić?

Kristoffer
źródło
6
powinieneś przeczytać tldp.org/LDP/Bash-Beginners-Guide/html/…
Mehul Rathod

Odpowiedzi:

124

Argumenty, które dostarczają do bashscript pojawi się w zmiennych $1i $2oraz $3gdzie liczba odnosi się do argumentu.$0to samo polecenie.

Argumenty są oddzielone spacjami, więc jeśli podasz -fromi -tow poleceniu, znajdą się one również w tych zmiennych, więc w tym przypadku:

./ocrscript.sh -from /home/kristoffer/test.png -to /home/kristoffer/test.txt

Dostaniesz:

$0    # ocrscript.sh
$1    # -from
$2    # /home/kristoffer/test.png
$3    # -to
$4    # /home/kristoffer/test.txt

Łatwiej byłoby pominąć -fromi -to, na przykład:

ocrscript.sh /home/kristoffer/test.png /home/kristoffer/test.txt

Wtedy będziesz miał:

$1    # /home/kristoffer/test.png
$2    # /home/kristoffer/test.txt

Wadą jest to, że będziesz musiał dostarczyć go we właściwej kolejności. Istnieją biblioteki, które mogą ułatwić analizowanie nazwanych argumentów w wierszu poleceń, ale zwykle w przypadku prostych skryptów powłoki powinieneś po prostu użyć prostego sposobu, jeśli nie stanowi to problemu.

Następnie możesz:

/usr/local/bin/abbyyocr9 -rl Swedish -if "$1" -of "$2" 2>&1

Podwójne cudzysłowy wokół $1i $2nie zawsze są konieczne, ale są adviced, ponieważ niektóre ciągi nie będzie działać, jeśli nie umieścić je między cudzysłów.

gitaarik
źródło
69

Jeśli nie jesteś całkowicie przywiązany do używania „od” i „do” jako nazw opcji, dość łatwo zaimplementować to za pomocą getopts :

while getopts f:t: opts; do
   case ${opts} in
      f) FROM_VAL=${OPTARG} ;;
      t) TO_VAL=${OPTARG} ;;
   esac
done

getopts to program, który przetwarza argumenty wiersza poleceń i wygodnie je analizuje.

f:t:określa, że ​​oczekujesz 2 parametrów zawierających wartości (wskazane przez dwukropek). Coś jak to f:t:vmówi-v będzie interpretowane tylko jako flaga.

optsto miejsce, w którym przechowywany jest bieżący parametr. PlikcaseStwierdzenie jest gdzie można przetworzyć tego.

${OPTARG}zawiera wartość następującą po parametrze. ${FROM_VAL}na przykład otrzyma wartość/home/kristoffer/test.png jeśli uruchomiłeś swój skrypt, taki jak:

ocrscript.sh -f /home/kristoffer/test.png -t /home/kristoffer/test.txt

Jak sugerują inni, jeśli po raz pierwszy piszesz skrypty basha, powinieneś naprawdę zapoznać się z podstawami. To był tylko krótki samouczek dotyczący getoptsdziałania.

Manny D.
źródło
1
Wydaje się, że jest to czytelne rozwiązanie. Jak więc określiłbyś dwie flagi?
Zelphir Kaltstahl
@Zelphir, możesz określić dwie lub więcej flag, po prostu pomijając znak „:” po fladze. Na przykład f:t:vsbędzie-f some_f -t some_t -v -s
h_s
34

Używać zmiennych "$1", "$2", "$3"i tak dalej do argumentów dostępu. Aby uzyskać dostęp do wszystkich, możesz użyć "$@"lub uzyskać liczbę argumentów $#(może być przydatne sprawdzenie, czy nie ma za mało lub za dużo argumentów).

StianE
źródło
24

Musiałem się upewnić, że moje skrypty są całkowicie przenośne między różnymi maszynami, powłokami, a nawet wersjami Cygwin. Co więcej, moi koledzy, dla których musiałem pisać skrypty, są programistami, więc skończyło się na tym:

for ((i=1;i<=$#;i++)); 
do

    if [ ${!i} = "-s" ] 
    then ((i++)) 
        var1=${!i};

    elif [ ${!i} = "-log" ];
    then ((i++)) 
        logFile=${!i};  

    elif [ ${!i} = "-x" ];
    then ((i++)) 
        var2=${!i};    

    elif [ ${!i} = "-p" ]; 
    then ((i++)) 
        var3=${!i};

    elif [ ${!i} = "-b" ];
    then ((i++)) 
        var4=${!i};

    elif [ ${!i} = "-l" ];
    then ((i++)) 
        var5=${!i}; 

    elif [ ${!i} = "-a" ];
    then ((i++)) 
        var6=${!i};
    fi

done;

Uzasadnienie: Dołączyłem również launcher.shskrypt, ponieważ cała operacja składała się z kilku kroków, które były od siebie prawie niezależne (mówię „quasi”, ponieważ chociaż każdy skrypt można było uruchomić samodzielnie, zwykle wszystkie były uruchamiane razem ) i po dwóch dniach dowiedziałem się, że około połowa moich kolegów, programistów i wszyscy, byli zbyt dobrzy, aby korzystać z pliku programu uruchamiającego, śledzić jego „użycie” lub przeczytać POMOC, która wyświetlała się za każdym razem, gdy coś robili źle i robili bałagan, uruchamiając skrypty z argumentami w złej kolejności i narzekając, że skrypty nie działają poprawnie. Będąc cholerykiem, zdecydowałem się odświeżyć wszystkie moje scenariusze, aby upewnić się, że są odporne na współpracowników. Segment kodu powyżej był pierwszą rzeczą.

user1628658
źródło
2
Lubię to. Dodaję sekcję na końcu `else echo" Nieprawidłowy argument: $ {! I} "((i ++))
fi`
6

W bashu $1jest to pierwszy argument przekazywany do skryptu, $2drugi i tak dalej

/usr/local/bin/abbyyocr9 -rl Swedish -if "$1" -of "$2" 2>&1

Możesz więc użyć:

./your_script.sh some_source_file.png destination_file.txt

Wyjaśnienie podwójnych cudzysłowów;

rozważ trzy skrypty:

# foo.sh
bash bar.sh $1

# cat foo2.sh
bash bar.sh "$1"

# bar.sh
echo "1-$1" "2-$2"

Teraz wywołaj:

$ bash foo.sh "a b"
1-a 2-b

$ bash foo2.sh "a b"
1-a b 2-

Kiedy wywołujesz foo.sh "a b", wywołuje bar.sh a b(dwa argumenty), a wraz z foo2.sh "a b"nim wywołuje bar.sh "a b"(1 argument). Zawsze miej na uwadze, w jaki sposób parametry są przekazywane i rozszerzane w bashu, dzięki temu zaoszczędzisz wiele bólu głowy.

Jakub M.
źródło