Parâmetros de script no Bash

103

Estou tentando fazer um script de shell que deve ser usado assim:

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

O script irá então converter o arquivo de imagem em um arquivo de texto. Aqui está o que eu descobri até agora:

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

Mas não sei como obter os valores -frome -to. Alguma ideia de como fazer isso?

Kristoffer
fonte
6
você deve ler tldp.org/LDP/Bash-Beginners-Guide/html/…
Mehul Rathod

Respostas:

124

Os argumentos que você fornece para um bashscript aparecerão nas variáveis $1e $2e $3onde o número se refere ao argumento. $0é o próprio comando.

Os argumentos são separados por espaços, portanto, se você fornecer o -frome -tono comando, eles terminarão nessas variáveis ​​também, para isso:

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

Você terá:

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

Pode ser mais fácil omitir o -frome o -to, como:

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

Então você terá:

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

A desvantagem é que você terá que fornecê-lo na ordem certa. Existem bibliotecas que podem tornar mais fácil analisar argumentos nomeados na linha de comando, mas geralmente para scripts de shell simples, você deve usar o caminho mais fácil, se não houver problema.

Então você pode fazer:

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

As aspas duplas em torno de $1e $2nem sempre são necessárias, mas são recomendadas, porque algumas strings não funcionarão se você não as colocar entre aspas duplas.

gitaarik
fonte
69

Se você não estiver completamente apegado ao uso de "from" e "to" como nomes de opções, é bastante fácil implementar isso usando getopts :

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

getopts é um programa que processa argumentos de linha de comando e os analisa convenientemente para você.

f:t:especifica que você está esperando 2 parâmetros que contêm valores (indicados por dois pontos). Algo como f:t:vdiz que -vsó será interpretado como uma bandeira.

optsé onde o parâmetro atual é armazenado. A casedeclaração é onde você processará isso.

${OPTARG}contém o valor após o parâmetro. ${FROM_VAL}por exemplo, obterá o valor /home/kristoffer/test.pngse você executou seu script como:

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

Como os outros estão sugerindo, se esta é sua primeira vez escrevendo scripts bash, você deve realmente ler alguns princípios básicos. Este foi apenas um rápido tutorial de como getoptsfunciona.

Manny D
fonte
1
Esta parece ser uma solução legível. Como você especificaria duas bandeiras então?
Zelphir Kaltstahl
@Zelphir, você pode especificar dois ou mais sinalizadores simplesmente omitindo o ":" após o sinalizador. Por exemplo f:t:vs, será-f some_f -t some_t -v -s
h_s
34

Use as variáveis "$1", "$2", "$3"e assim por diante para argumentos de acesso. Para acessar todos eles, você pode usar "$@"ou para obter a contagem de argumentos $#(pode ser útil verificar se há poucos ou muitos argumentos).

StianE
fonte
24

Eu precisava ter certeza de que meus scripts são totalmente portáveis ​​entre várias máquinas, shells e até mesmo versões do cygwin. Além disso, meus colegas, para quem eu tive que escrever os scripts, são programadores, então acabei usando isto:

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;

Fundamentação da petição: também incluí um launcher.shscript, uma vez que toda a operação tinha vários passos que eram quase independentes entre si (estou a dizer "quase", porque embora cada script pudesse ser executado sozinho, normalmente eram todos executados juntos ), e em dois dias eu descobri que cerca de metade dos meus colegas, sendo programadores e todos, eram bons demais para usar o arquivo do iniciador, seguir o "uso" ou ler a AJUDA que era exibida toda vez que eles faziam algo errados e eles estavam bagunçando tudo, executando scripts com argumentos na ordem errada e reclamando que os scripts não funcionavam corretamente. Sendo o colérico que sou, decidi revisar todos os meus scripts para ter certeza de que são à prova de colegas. O segmento de código acima foi a primeira coisa.

user1628658
fonte
2
Eu gosto disso. Estou adicionando uma seção no final `else echo" Argumento inválido: $ {! I} "((i ++))
fi`
6

Em bash $1é o primeiro argumento passado para o script, o $2segundo e assim por diante

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

Então você pode usar:

./your_script.sh some_source_file.png destination_file.txt

Explicação sobre aspas duplas;

considere três scripts:

# foo.sh
bash bar.sh $1

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

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

Agora invoque:

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

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

Quando você invoca foo.sh "a b", ele invoca bar.sh a b(dois argumentos) e, com foo2.sh "a b"ele, bar.sh "a b"(1 argumento). Sempre tenha em mente como os parâmetros são passados ​​e expandidos no bash, isso o salvará de muitas dores de cabeça.

Jakub M.
fonte