Diferencia entre revisiones de «Scripts Bash»
Sin resumen de edición |
|||
Línea 318: | Línea 318: | ||
http://www.pixelbeat.org/programming/shell_script_mistakes.html | http://www.pixelbeat.org/programming/shell_script_mistakes.html | ||
http://serverfault.com/questions/7503/how-to-determine-if-a-bash-variable-is-empty |
Revisión del 17:41 16 may 2013
Redirecciones
$ cmd > fichero
Redirige la salida estandar a un fichero.
$ cmd 2> fichero
Redirige la salida de error a un fichero.
$ cmd >> fichero
Añade a un fichero la salida estandar sin borrar el contenido anterior.
$ cmd 2>> fichero
Añade los errores al final de un fichero.
$ cmd &> fichero
Redirige la salida estandar y la de error a un fichero.
$ cmd > fichero 2>&1
$ cmd 2>&1 >>ficheroPorque no funcionará, ya que evalúa de izquierda a derecha. Es decir, primero envíael error a la salida estándar 1 que es la terminal y luego la salida estándar la modifica por el fichero. Pero ya ha salido el error por pantalla
Otra manera de redirigir las dos salidas a un fichero.
$ cmd > /dev/null $ cmd 2> /dev/null $ cmd &> /dev/null
Descartar la salida estándar, la de error o las dos.
$ cmd < fichero
Redirige el contenido de un fichero a la entrada estandar del comando.
$ cmd << FIN linea1 linea2 FIN
Redirige una serie de líneas a un comando. Esto se llama Here-Document. La palabra FIN sólo es para indicar el final de las líneas y puede ser cualquier otra.
$ cmd <<< "palabra"
Redirecciona el texto al comando. Se llama here-string.
$ exec 2> fichero
Redirige la salida de error a un fichero para todos los comandos.
$ exec 3< fichero
Abre un fichero para leer usando un nuevo descriptor.
$ exec 3> fichero
Abre un fichero para escribir usando un nuevo descriptor.
$ exec 3<> fichero
Abre un fichero para leer o escribir usando el descriptor 3.
$ exec 3>&-
Cierra un descriptor de fichero.
# open it exec 3< input.txt # for example: read one line from the file(-descriptor) read -u 3 LINE # or read LINE <&3 # finally, close it exec 3<&-
read interactivo de ficheros
$ seq 30 > numeros
Observemos este script:
#!/bin/bash # cada 10 linies espera a que l'usuari escriga alguna cosa while read Num do let ContLin++ # Contando... echo -n "$Num " # -n para no saltar línea ((ContLin % 10)) > /dev/null || read done < numeros
El resultado es este:
1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29 30
Y no se espera a que el usuario ponga nada.
Esto es porque el read de dentro del bucle lee también del fichero. Se puede forzar a que lea de la terminal:
#!/bin/bash # cada 10 linies espera a que l'usuari escriga alguna cosa while read Num do let ContLin++ # Contando... echo -n "$Num " # -n para no saltar línea ((ContLin % 10)) > /dev/null || read < /dev/tty done < numeros
O se puede crear un descriptor de fichero y modificar el read del while:
#!/bin/bash # cada 10 linies espera a que l'usuari escriga alguna cosa exec 3< numeros while read Num <&3 do let ContLin++ # Contando... echo -n "$Num " # -n para no saltar línea ((ContLin % 10)) > /dev/null || read done
Process Substitution
Los comandos que necesitan un fichero, pueden ejecutarse con el |, por ejemplo el wc puede hacerse:
$ cat /etc/passwd | wc -l
A veces un comando acepta como entrada dos ficheros. En ese caso, el ejemplo anterior no se puede seguir. Para solucionarse, se pueden usar los () después de una < [1]
$ diff <(ls $first_directory) <(ls $second_directory)
Variables y argumentos
- $0: Nombre del script.
- $1,$2,$3...$9 Argumentos. En principio no se puede poner más de 9 argumentos. Si se quiere poner 10 o más, se puede recurrir al shift o poniéndolo como ${12}
- $# Candidad de argumentos
- $* Todos los argumentos
- $? : a 0 si el comando anterior ha terminado sin dar error. A 1 o más si ha dado error.
- $_ : El primer argumento del comando anterior
shift
Este comando permite usar un mismo número de argumento para ir recorriéndolos.
En este ejemplo se ve bastante bien. Via
while test -n "$1"; do case "$1" in -a) opciona=$2 shift ;; -b) opcionb=$2 shift ;; -c) opcionc=$2 shift ;; -d) opciond=$2 shift ;; *) echo "Unknown argument: $1" exit 0 ;; esac shift done
El while recorre todos los argumentos, aunque sólo comprueba el $1 en cada iteración, se queda con $2 y pasa al siguiente. De esta manera, el órden de los argumentos y sus opciones no es relevante.
# miscript -a opciona -b opcionb -d opciond # miscript -b opcionb -c opcionc
Interpretación de los argumentos por el shell
El shell se encarga de sustituir los caracteres de sustitución y las variables antes de pasar los argumentos a un comando o script. Esto se puede ver con este script:
#!/bin/bash echo $* echo $#
Si se invoca de estas maneras, por ejemplo:
$ ./argumentos * $ ./argumentos p[a-z] $ ./argumentos {1..100} $ ./argumentos $HOME
Tests
El [ para hacer test se puede usar en todos los shell que cumplen con POSIX. Mientras que el doble [[ está en bash y otros shells modernos.
#POSIX [ "$variable" ] || echo 'variable is unset or empty!' >&2 [ -f "$filename" ] || printf 'File does not exist: %s\n' "$filename" >&2
Saber más:
$ whereis [ [: /usr/bin/[ /usr/share/man/man1/[.1.gz $ man [
Los dobles [[ no son un comando, sino que forman parte del bash.
Funciones | ||
---|---|---|
Función | Expresión | Ejemplo |
Comparación de strings | < , > , = , == != |
[[ a > b ]] || echo "a does not come before b" [[ az < za ]] && echo "az comes before za" |
Comparación de integers | -ge , -gt , -lt , -le , -eq , -ne |
[[ 6 -ne 20 ]] && echo "6 is not equal to 20" |
Condicional | || , && |
[[ -n $var && -f $var ]] && echo "$var is a file" |
Agrupar | (...) (obsoleto) |
[[ $var = img* && ($var = *.png || $var = *.jpg) ]] && echo "$var starts with img and ends with .jpg or .png" |
Patrones | = o == |
[[ $name = a* ]] || echo "name does not start with an 'a': $name" |
Expresión regular | =~ |
[[ $(date) =~ ^Fri\ ...\ 13 ]] && echo "It's Friday the 13th" |
Negación | ! |
[[ ! -u $file ]] && echo "$file is not a setuid file" |
Ejemplos con ficheros:
[[ -e $config ]] && echo "config file exists: $config" [[ $file0 -nt $file1 ]] && echo "$file0 is newer than $file1" [[ $input -ef $output ]] && { echo "will not overwrite input file: $input"; exit 1; }
Se recomienda usar [[ si el nombre de los ficheros puede tener espacios en blanco:
file="file name" [[ -f $file ]] && echo "$file is a file"
via:[2]
Expresiones aritméticas
El comando típico para hacer operaciones matemáticas es let
let a=17+23 let a="17 + 23"
Pero es más útil usar (()), ya que puedes usar un $ delante $(()). Permite usar espacios en blanco y no necesita usar $ en las variables porque no están permitidas cadenas dentro.
((a=$a+7)) # Add 7 to a ((a = a + 7)) # Add 7 to a. Identical to the previous command. ((a += 7)) # Add 7 to a. Identical to the previous command. ((a = RANDOM % 10 + 1)) # Choose a random number from 1 to 10. # % is modulus, as in C. # (( )) may also be used as a command. > or < inside (( )) means # greater/less than, not output/input redirection. if ((a > 5)); then echo "a is more than 5"; fi
Los (()) sin $ delante sólo va en bash. Los siguientes ejemplos son compatibles con todos los POSIX
a=$((a+7)) # POSIX-compatible version of previous code. if test $((a%4)) = 0; then ...
via: [3]
Enlaces
http://mywiki.wooledge.org/BashGuide/Practices
http://www.pixelbeat.org/programming/shell_script_mistakes.html
http://serverfault.com/questions/7503/how-to-determine-if-a-bash-variable-is-empty