Enrique Ocaña González
chucky_spain@hotmail.com
La entrada y la salida de comandos se puede redirigir y encadenar de las siguientes formas:
$ grep Linux < entrada.txt
$ cat /dev/audio > sonido_grabado.au
$ grep Linux < entrada.txt > salida.txt
$ ps ax | grep "\ R\ "
5348 ttyp0 R 0:00 ps ax
$ cat << FIN
> Este es mi mensaje largo
> de 2 lineas
> FIN
Este es mi mensaje largo
de 2 lineas
TRUCO: Se pueden expandir variables en el texto, de modo que resulta muy fácil hacer plantillas$ CUENTAS=`ls /home`
$ for cuenta in ${CUENTAS}; do cat <<FIN
> He encontrado la cuenta ${cuenta} en el sistema
> FIN
> done
He encontrado la cuenta enrique en el sistema
He encontrado la cuenta gm en el sistema
He encontrado la cuenta magic en el sistema
$ echo 'La pantalla ha explotado' >> eventos.log
$ sort 0<mi_fichero.txt (Otra forma alternativa de redirigir la entrada estándar)
$ ls pepe 2>>errores.txt (Hemos redirigido el Error Estándar (descriptor n2) al fichero errores.txt en modo Append)
$ ls pepe >>salida_y_errores.txt 2>&1 (Hemos redirigido la Salida Estándar (descriptor n1) a un fichero en modo Append, y luego hemos redirigido el error estándar (descriptor n
2) al mismo fichero que está siendo utilizado por el descriptor 1 (el de la salida estándar))
$ ls >&- (La salida del comando no va a ninguna parte y por eso ls nos va a dar un error)
ls: error de escritura: Descriptor de fichero erróneo
#!/bin/sh
# Script que vuelca el contenido de /home y /tmp al fichero cosas.txt
exec >>cosas.txt (Esta es la parte que redirige toda la salida de lo que viene a continuación)
ls /home
ls /tmp
$ USERS=`cat /etc/passwd | cut -f1 -d:`
$ for user in ${USERS}
> do
> du -sk /home/${user}
> done >>diskusage 2>/dev/null (Aquí se hace la redirección)
$ cat diskusage
2748 /home/ftp
38931 /home/jac
109 /home/mlambi
26151 /home/rsayle
5 /home/bobt
8185 /home/mann_al
13759 /home/bheintz
Los comandos simples de un shell pueden ser agrupados de las siguientes formas:
$ ls > /tmp/listado; ls -lisa > /tmp/listado_detallado
$ TMP=permanece; (TMP=no_me_ves; echo $TMP); echo $TMP
$ TMP=permanece; { TMP=no_me_ves; echo $TMP; }; echo $TMP
$ ls pepe && echo 'El directorio pepe existe'
$ ls pepe || echo 'El directorio pepe no existe'
Una expresión regular es una secuencia de caracteres que especifica un patrón textual. Se utilizan en muchos comandos de UNIX, como por ejemplo grep, sed, awk y egrep. Mediande ellas se puede indicar a los programas que procesen sólo aquellos elementos que encajen con el patrón. La mayoría de las expresiones regulares utilizan metacaracteres para expresar repetición, existencia o rangos en patrones de caracteres.
A continuación se describen los metacaracteres más comunes:
El shell utiliza algo parecido a las expresiones regulares para emparejar con los nombres de fichero de un directorio (parecido a lo que ocurre en MS-DOS). Este es el juego de metacaracteres propios que utiliza el shell:
Carácter | Significado |
---|---|
* (Comodín) | Empareja con 0 o más caracteres |
? | Empareja con 1carácter |
[abc...] | Empareja con cualquiera de los caracteres listados |
[!abc...] | Empareja con lo contrario que [abc...] |
\ (Escape) | Elimina el significado de cualquier carácter especial, incluido fin de línea |
Estos los los tipos de comillas que se utilizan en scripting:
$ SYS=Linux ; echo "Este es un sistema $SYS equipado"
Este es un sistema Linux equipado
$ SYS=Linux ; echo 'Este es un sistema $SYS equipado'
Este es un sistema $SYS equipado
$ echo "El nombre del sistema es \"`hostname`\" "
El nombre del sistema es "chucky"
$ echo Un asterisco: \*
Un asterisco: *
Las variables se declaran con un = sin espacios. A menudo es recomendable utilizar comillas.
Para desreferenciar una variable se coloca un $ delante de su nombre. Para diferenciar el nombre de la variable de lo que viene a continuación es aconsejable colocal la variable entre llaves { }:
#!/bin/sh
NOMBRE='John Smith'
echo $NOMBRE
$ CARA="*Cara*"; CARACOL="*Caracol*"; echo $CARACOL; echo ${CARA}COL
*Caracol*
*Cara*COL
La sustitución de parámetros es un método para dotar de un valor por defecto a una variable en el caso de que no esté definida (valga nulo). Existen varios tipos de sustitución de parámetros:
$ echo "El nombre es ${NOMBRE:-desconocido}"
El nombre es desconocido
$ NOMBRE=pepe; echo "El nombre es ${NOMBRE:-desconocido}"
El nombre es pepe
$ echo "Antes: ${NOMBRE}, Ahora: ${NOMBRE:='John Smith'}, Despues: ${NOMBRE}"
Antes: , Ahora: 'John Smith', Despues: 'John Smith'
$ echo "El nombre es ${NOMBRE:?}"
bash: NOMBRE: parameter null or not set
$ echo "*${NOMBRE:+Existe}*"; NOMBRE=Pepe; echo "*${NOMBRE:+Existe}*"
**
*Existe*
Las variables pueden declararse como de sólo-lectura mediante readonly:
$ NOMBRE=PepeAdemás, los valores de las variables que se asignan en el shell actual (variables locales) no son heredados por los subshells que lancemos desde el actual. Para que los subshells puedan ver las variables locales es necesario exportarlas:
$ NOMBRE=Juan
$ readonly NOMBRE
$ NOMBRE=Pepe
bash: NOMBRE: readonly variable
$ export DISPLAY='localhost:0.0'
A continuación se muestra una tabla con variables del shell que contienen valores especiales:
Variable | Contenido |
---|---|
$0 ... $9 | Nombre del ejecutable del shell ($0) y los primeros 9 argumentos |
$# | Número de argumentos pasados al shell |
$* | Valor de los argumentos como un único valor |
$@ | Como $*pero cuando se pone entre comillas dobles, pone cada parám. entre com. dobles. |
$$ | PID del script o la sesión actual |
$! | PID del último programa enviado al background |
$? | Exit status del último programa no ejecutado en background |
$- | Opciones actuales en efecto |
Cuando se deseen pedir datos del usuario o de la Entrada Estándar se deberá utilizar el comando read:
$ read PERSONA CIUDAD HOBBY; echo "$PERSONA vive en $CIUDAD y practica $HOBBY"Los campos en la entrada se separan generalmente por espacios, avances de línea y tabuladores, pero este comportamiento puede ser modificado combiando el valor de la variable de entorno IFS (Internal Field Separator), que contiene los caracteres que actúan de separadores:
Pepe New\ York pesca
Pepe vive en New York y practica pesca
$ export IFS=":"
$ read PERSONA CIUDAD HOBBY; echo "$PERSONA vive en $CIUDAD y practica $HOBBY"
Pepe:New York:pesca
Pepe vive en New York y practica pesca
Las funciones se declaran así:
miFuncion () {El espacio entre el nombre de la función y los paréntesis no es obligatorio, así como tampoco lo es que la apertura de llave aparezca en la misma línea que la declaración de la función. Es importante decir que los argumentos de una función nunca se declaran, de modo que los paréntesis deben aparecer siempre vacíos.
echo 'Hola!!'
echo 'Soy una función :-)'
}
otraFuncion () { echo 'Pues yo soy otra función ;-)'; }
Para llamar a la función, simplemente se le llama, pasándole todos los parámetros que sea necesario. Los parámetros se referencian del mismo modo que en el shell: $1, $2, $3... y el resultado de la función se declara con return y se lee luego con la variable de entorno $?. Si una función no retorna nada, en $? queda almacenado el valor de retorno de la última sentencia que se ejecutó al llamar a la función.
$ felicitacion () {Los cambios realizados en las variables dentro de una función no son locales, es decir, permanecen al finalizar la llamada a la función (al contrario de lo que ocurre al abrir un subshell). Del mismo modo, las variables declaradas (mediante una asignación) dentro de una función quedan declaradas para todo el script.
> echo "Feliz cumpleaños ${1}!!"
> return ${2}
>}
$ felicitacion Jonh 16
Feliz cumpleaños John!!
$ echo $?
16
Para incluir (como con el #include de C) el contenido de un fichero (que podría tener muchas funciones útiles definidas) en el script actual se utiliza el comando punto ( . ):
#!/bin/sh
# FICHERO utilHTML.sh
cabeceraHTML() { echo '<HTML><BODY>'; }
cierreHTML() { echo '</BODY></HTML>'; }
documentoHTML () {
cabeceraHTML
echo ${1}
cierreHTML
}
#!/bin/sh
# FICHERO saludo.sh
. utilHTML.sh
documentoHTML 'Hola World Wide Web!!'
Existen dos formas de chequear una condición dejando el resultado (0 si es Verdadera o 1 si es Falsa) en la variable $?:
Comprobación | Significado |
---|---|
string | string no es nulo |
-n string | string no es nulo |
-z string | string sí es nulo |
string1 = string2 | string1 es igual a string2 |
string1 != string2 | string1 no es igual a string2 |
-eq | igual a (eq va en medio de los valores a comparar) |
-ne | no igual |
-gt | mayor que |
-ge | mayor o igual |
-lt | menor que |
-le | menor o igual |
-b | el fichero es un fichero especial de bloque |
-c | es un fichero especial de carácter |
-d | es un directorio |
-f | es un fichero ordinario |
-g | tiene el Set Group ID Bit activado |
-k | tiene el Sticky Bit activado |
-p | es un Named Pipe |
-r | puede ser leído por el proceso actual |
-s | tiene longitud distinta de 0 |
-t | el descriptor de fichero está abierto y asociado a un terminal |
-u | tiene el Set User ID Bit activado |
-w | puede ser escrito por el proceso actual |
-x | puede ser ejecutado por el proceso actual |
-a | hace un AND del argumento anterior y siguiente |
-o | hace un OR del argumento anterior y siguiente |
Los IFs se declaran de la siguiente manera:
if [ $n < 5 ]; then
echo 'Es...'
echo '...menor que 5'
elif [ $n > 5 ]; then
echo 'Es...'
echo '...mayor que 5'
else
echo 'Es...'
echo '...igual a 5'
fi
Tambien podemos declarar estructuras CASE, donde se hace pattern-matching con cada caso, que sólo será ejecutado si empareja con la expresión regular:
case ($opcion) in
-h) echo 'Este script no tiene ayuda'
;;
-n) echo 'El nombre de la máquina es:'
hostname
;;
*) echo 'Cualquier opción que no sea -h, -n no es válida'
;;
esac
La forma de declarar un bucle FOR es:
for variable in 1 2 3 /tmp/* ` ls -lisa` items_de_una_listaSi se omite la lista de valores del FOR, el shell utiliza la lista de parámetros posicionales $1...$9 condensada en $@:
do
echo 'Un item:'
echo $variable
done
#!/bin/sh
# FICHERO imprime_parametros.sh
echo $@
for p
do
echo "Un parámetro: ${p}"
done
$ imprime_parametros.sh Hola mundo
Hola mundo
Un parámetro: Hola
Un parámetro: mundo
El bucle se ejecuta mientras se cumpla la condición:
$ i=1Los bucles WHILE pueden ser utilizados para realizar la técnica conocida como ``desplazamiento de argumentos'':
$ while [ ${i} -le 5 ]
> do
> echo ${i}
> i=`expr ${i} + 1`
> done
1
2
3
4
5
$ cat printargs
#!/bin/sh
while [ $# -gt 0 ]
do
echo "$@"
shift
done
$ printargs hello world "foo bar" bye
hello world foo bar bye
world foo bar bye
foo bar bye
bye
El bucle se ejecuta hasta que se cumpla la condición:
$ cat printargs2
#!/bin/sh
until [ $# -le 0 ]
do
echo "$@"
shift
done
$ printargs2 hello world "foo bar" bye
hello world foo bar bye
world foo bar bye
foo bar bye
bye
Existen dos comandos para controlar las iteraciones de un bucle:
Tradicionalmente en UNIX existen dos formas de reconocer parámetros:
#!/bin/shY se puede hacer aún de forma más sencilla utilizando la utilidad getopts:
#
# setether: set an Ethernet interface's IP configuration
#
while [ $# -gt 1 ]
do
case ${1}
a) ARP="arp"
shift
;;
b) BROADCAST=${2}
shift 2
;;
i) IPADDRESS=${2}
shift 2
;;
m) NETMASK=${2}
shift 2
;;
n) NETWORK=${2}
shift 2
;;
*) echo "setether: illegal option: ${1}"
exit 1
;;
esac
done
INTERFACE=${1}
ifconfig ${INTERFACE} ${IPADDRESS} netmask ${NETMASK} broadcast ${BROADCAST} ${ARP}
route add -net ${NETWORK}
#!/bin/shComo el parámetro ``a'' no lleva nada, getopts sabe que no debe buscarle un argumento. Sin embargo, los dos puntos de ``b:'', ``e:'', ``i:``, ``m:`` y ``n:`` indican que esto parámetros sí llevan argumentos, que getopts deberá buscar y colocar en la variable de entorno $OPTARG. Además podemos observar cómo ya no es necesario realizar a mano el desplazamiento (shift) de la lista de argumentos, puesto que de eso ya se encarga getopts.
#
# setether: set an Ethernet interface's IP configuration
#
while getopts ab:e:i:m:n: option
do
case "${option}" in
a) ARP="arp"
b) BROADCAST=${OPTARG};;
e) INTERFACE=${OPTARG};;
i) IPADDRESS=${OPTARG};;
m) NETMASK=${OPTARG};;
n) NETWORK=${OPTARG};;
*) echo "setether: illegal option: ${option}"
exit 1
;;
esac
done
INTERFACE=${1}
ifconfig ${INTERFACE} ${IPADDRESS} netmask ${NETMASK} broadcast ${BROADCAST} ${ARP}
route add -net ${NETWORK}
El uso de getopts agiliza la tarea de interpretar argumentos, aunque tiene desventajas como que sólo puede manejar opciones con un único carácter. Si queremos reconocer, por ejemplo, la opción ``-help'' tendremos que hacerlo a mano.
This document was generated using the LaTeX2HTML translator Version 99.2beta6 (1.42)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -no_subdir -split 0 -show_section_numbers /home/enrique/Desktop/Notas/bash.tex
The translation was initiated by Debian Linux User on 2000-10-17