2009-03-31 35 views
78

Se me ocurrió uno básico para ayudar a automatizar el proceso de eliminación de un número de carpetas a medida que se vuelven innecesarias.Validación de parámetros en un script Bash

#!/bin/bash 
rm -rf ~/myfolder1/$1/anotherfolder 
rm -rf ~/myfolder2/$1/yetanotherfolder 
rm -rf ~/myfolder3/$1/thisisafolder 

Esto se evoca así:

./myscript.sh <{id-number}> 

El problema es que si se olvida de escribir el id-number(como lo hice en ese momento), entonces podría potencialmente eliminar una gran cantidad de cosas que realmente no quieres borrar

¿Existe alguna forma de que pueda agregar algún tipo de validación a los parámetros de la línea de comando? En mi caso, sería bueno comprobar que a) hay un parámetro, b) es numérico, yc) esa carpeta existe; antes de continuar con el guion

Respuesta

129
#!/bin/sh 
die() { 
    echo >&2 "[email protected]" 
    exit 1 
} 

[ "$#" -eq 1 ] || die "1 argument required, $# provided" 
echo $1 | grep -E -q '^[0-9]+$' || die "Numeric argument required, $1 provided" 

while read dir 
do 
    [ -d "$dir" ] || die "Directory $dir does not exist" 
    rm -rf "$dir" 
done <<EOF 
~/myfolder1/$1/anotherfolder 
~/myfolder2/$1/yetanotherfolder 
~/myfolder3/$1/thisisafolder 
EOF 

edición: Me perdí la parte sobre la comprobación de si existen los directorios en un primer momento, por lo que añade que, en, completando el guión. Además, se han abordado cuestiones planteadas en los comentarios; corrigió la expresión regular, cambió de == a eq.

Esto debería ser una secuencia de comandos portátil compatible con POSIX hasta donde yo sepa; no utiliza ningún bashisms, que es realmente importante porque /bin/sh en Ubuntu es realmente dash actualmente, no bash.

+1

me gusta por compacidad – ojblass

+0

recuerde establecer + e y use '-eq' en lugar de '==' para las comparaciones enteras – guns

+0

Se ha cambiado a -eq; ¿Qué te hace + e comprar aquí? –

7

Utilice '-z' para comprobar las cadenas vacías y '-d para buscar directorios.

if [[ -z "[email protected]" ]]; then 
    echo >&2 "You must supply an argument!" 
    exit 1 
elif [[ ! -d "[email protected]" ]]; then 
    echo >&2 "[email protected] is not a valid directory!" 
    exit 1 
fi 
+1

¿Por qué necesita el doble [[]]? – vehomzzz

10

No como prueba de balas como la respuesta anterior, sin embargo sigue siendo eficaz:

#!/bin/bash 
if [ "$1" = "" ] 
then 
    echo "Usage: $0 <id number to be cleaned up>" 
    exit 
fi 

# rm commands go here 
5

El hombre de la página de prueba (man test) proporciona todos los operadores disponibles que puede utilizar operadores booleanos como en bash. Utilice esos indicadores al comienzo de su secuencia de comandos (o funciones) para la validación de entrada al igual que lo haría en cualquier otro lenguaje de programación. Por ejemplo:

if [ -z $1 ] ; then 
    echo "First parameter needed!" && exit 1; 
fi 

if [ -z $2 ] ; then 
    echo "Second parameter needed!" && exit 2; 
fi 
13

yo usaría de [[ bash:

if [[ ! ("$#" == 1 && $1 =~ ^[0-9]+$ && -d $1) ]]; then 
    echo 'Please pass a number that corresponds to a directory' 
    exit 1 
fi 

he encontrado this faq ser una buena fuente de información.

+0

'este faq' resucitó :) –

20

La solución sh por Brian Campbell, aunque noble y bien ejecutada, tiene algunos problemas, así que pensé en proporcionar mi propia solución bash.

Los problemas con el sh uno:

  • La tilde en ~/foo no se expande a su directorio personal en el interior heredocs. Y tampoco cuando se lee en la declaración read o se cita en la declaración rm. Lo que significa que obtendrá No such file or directory errores.
  • La bifurcación de grep y tal para operaciones básicas es tonto. Especialmente cuando estás usando una cáscara de mierda para evitar el peso "pesado" de bash.
  • También noté algunos problemas de cotización, por ejemplo, alrededor de una expansión de parámetro en su echo.
  • Aunque es raro, la solución no puede hacer frente a los nombres de archivo que contienen líneas nuevas. (Casi ninguna solución en sh puede hacerles frente - por eso casi siempre prefiero bash, es mucho más resistente a balas & más difícil de explotar si se usa bien).

Aunque, eso sí, utilizando /bin/sh para su Hashbang significa que debe evitar bash ismos a toda costa, puede utilizar todos los ismos bash te gusta, incluso en Ubunutu o lo que sea, cuando uno es honesto y poner en el #!/bin/bash parte superior.

Por lo tanto, aquí hay una solución bash que es más pequeña, más limpia, más transparente, probablemente "más rápida" y más a prueba de balas.

[[ -d $1 && $1 != *[^0-9]* ]] || { echo "Invalid input." >&2; exit 1; } 
rm -rf ~/foo/"$1"/bar ... 
  1. Aviso las comillas alrededor de $1 en el estado rm!
  2. La comprobación -d también fallará si $1 está vacío, por lo que son dos comprobaciones en una.
  3. Evité las expresiones regulares por algún motivo. Si debe usar =~ en bash, debe colocar la expresión regular en una variable. En cualquier caso, globos como el mío son siempre preferibles y compatibles en muchas más versiones de bash.
+1

Entonces, ¿es la pieza globbing '$ 1! = * [^ 0-9] *' bash specific then? – grinch

4

Puede validar los puntos A y B de forma compacta haciendo algo como lo siguiente:

#!/bin/sh 
MYVAL=$(echo ${1} | awk '/^[0-9]+$/') 
MYVAL=${MYVAL:?"Usage - testparms <number>"} 
echo ${MYVAL} 

Lo que nos da ...

$ ./testparams.sh 
Usage - testparms <number> 

$ ./testparams.sh 1234 
1234 

$ ./testparams.sh abcd 
Usage - testparms <number> 

Este método debería funcionar bien en sh.

1

Mensaje viejo pero pensé que podría contribuir de todos modos.

Una secuencia de comandos no puede ser necesaria y con cierta tolerancia a las comodines podría llevarse a cabo desde la línea de comandos.

  1. salvaje en cualquier lugar que coincida. Permite eliminar cualquier aparición de sub "carpeta"

  2. Shell reiteró. Deja para quitar las carpetas pre y post específicas con una línea

    $ rm -rf ~/foo{1,2,3}/folder/{ab,cd,ef} 
    
  3. Shell itera + var (BASH probado).

    $ var=bar rm -rf ~/foo{1,2,3}/${var}/{ab,cd,ef} 
    
Cuestiones relacionadas