Parámetros de script en Bash

103

Estoy tratando de hacer un script de shell que debería usarse así:

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

El script luego convertirá el archivo de imagen en un archivo de texto. Esto es lo que se me ocurrió hasta ahora:

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

Pero no sé cómo obtener los valores -fromy -to. ¿Alguna idea de cómo hacerlo?

Kristoffer
fuente
6
debería leer tldp.org/LDP/Bash-Beginners-Guide/html/…
Mehul Rathod

Respuestas:

124

Los argumentos que se suministre a un bashscript aparecerán en las variables $1y $2y $3donde el número se refiere al argumento. $0es el comando en sí.

Los argumentos están separados por espacios, por lo que si proporciona -fromy -toen el comando, también terminarán en estas variables, por lo que para esto:

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

Obtendrás:

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

Podría ser más fácil omitir el -fromy el -to, como:

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

Entonces tendrás:

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

La desventaja es que tendrás que suministrarlo en el orden correcto. Hay bibliotecas que pueden facilitar el análisis de los argumentos con nombre en la línea de comandos, pero generalmente para scripts de shell simples, debe usar la forma fácil, si no hay problema.

Entonces puedes hacer:

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

Las comillas dobles alrededor de $1y $2no siempre son necesarias, pero se recomiendan, porque algunas cadenas no funcionarán si no las pone entre comillas dobles.

gitaarik
fuente
69

Si no está completamente apegado a usar "from" y "to" como nombres de opciones, es bastante fácil implementar esto usando getopts :

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

getopts es un programa que procesa argumentos de línea de comando y los analiza convenientemente por usted.

f:t:especifica que está esperando 2 parámetros que contienen valores (indicados por dos puntos). Algo como f:t:vdice que -vsolo se interpretará como una bandera.

optses donde se almacena el parámetro actual. La casedeclaración es donde procesará esto.

${OPTARG}contiene el valor que sigue al parámetro. ${FROM_VAL}por ejemplo, obtendrá el valor /home/kristoffer/test.pngsi ejecutó su script como:

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

Como sugieren los demás, si es la primera vez que escribe scripts de bash, debería leer algunos conceptos básicos. Este fue solo un tutorial rápido sobre cómo getoptsfunciona.

Manny D
fuente
1
Esta parece ser una solución legible. ¿Cómo especificaría entonces dos banderas?
Zelphir Kaltstahl
@Zelphir, puede especificar dos o más banderas simplemente omitiendo el ":" después de la bandera. Por ejemplo f:t:vs, será-f some_f -t some_t -v -s
h_s
34

Utilizar las variables "$1", "$2", "$3"y así sucesivamente a los argumentos de acceso. Para acceder a todos ellos puede utilizar "$@", o para obtener el recuento de argumentos $#(puede ser útil para comprobar si hay demasiados argumentos o muy pocos).

StianE
fuente
24

Necesitaba asegurarme de que mis scripts fueran completamente portátiles entre varias máquinas, shells e incluso versiones de cygwin. Además, mis colegas, para quienes tuve que escribir los scripts, son programadores, así que terminé usando esto:

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;

Justificación: también incluí un launcher.shscript, ya que toda la operación tenía varios pasos que eran casi independientes entre sí (digo "cuasi", porque aunque cada script se podía ejecutar por sí solo, por lo general se ejecutaban todos juntos ), y en dos días descubrí que aproximadamente la mitad de mis colegas, que eran programadores y todo, eran demasiado buenos para usar el archivo de inicio, seguir el "uso" o leer la AYUDA que se mostraba cada vez que hacían algo. mal y estaban haciendo un lío con todo, ejecutando scripts con argumentos en el orden incorrecto y quejándose de que los scripts no funcionaban correctamente. Siendo el colérico que soy, decidí revisar todos mis guiones para asegurarme de que sean a prueba de colegas. El segmento de código anterior fue lo primero.

user1628658
fuente
2
Me gusta esto. Estoy agregando una sección al final `else echo" Argumento no válido: $ {! I} "((i ++))
fi`
6

En bash se $1pasa el primer argumento al script, el $2segundo y así sucesivamente

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

Entonces puedes usar:

./your_script.sh some_source_file.png destination_file.txt

Explicación sobre comillas dobles;

considere tres guiones:

# foo.sh
bash bar.sh $1

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

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

Ahora invoca:

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

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

Cuando invoca foo.sh "a b", invoca bar.sh a b(dos argumentos) y con foo2.sh "a b"él invoca bar.sh "a b"(1 argumento). Siempre tenga en cuenta cómo se pasan y expanden los parámetros en bash, esto le ahorrará muchos dolores de cabeza.

Jakub M.
fuente