4 - La shell (2)

[editar]
Curso gratis creado por Publispain. Extraido de: http://www.publispain.com
30 de Noviembre de 1999
- Comandos trap/exec/exit.

Como se vió en un capítulo anterior , cualquier proceso UNIX es susceptible de recibir señales a lo largo de su tiempo de ejecución. Por ejemplo , si el sistema se apaga (shutdown) , todos los procesos recibe n de entrada una señal 15 (SIGTERM) , y , al rato , una señal 9 .Por ahora , recordaremos que sólamente la señal 9 (SIGKILL) no puede ser ignorada ni redirigida . Un programa puede cambiar el tratamiento que los procesos hacen respecto de las señales , que suele ser terminar.

Las shell-scripts pueden efectuar cosas dependiendo de la señal que reciban , usando el comando "trap <comandos> <señales>" . Este comando se suele poner al principio de la shell para que siga vigente a lo largo de toda la ejecución.

Así , podemos directamente ignorar una señal escribiendo lo siguiente :

trap "" 15

(Si llega la señal 15 (SIGTERM) , no hagas nada)

O evitar que nos pulsen Control-C , y si lo hacen , se acabó :

trap ‘echo "Hasta luego lucas" ; exit 1’ 2 3 15

(Si llega cualquiera , sacar el mensajito y terminar la ejecución con código de retorno 1).

Ojo con la ejecución de subshells - las señales ignoradas (las del trap ‘’) se heredan pero las demás vuelven a su acción original.

El comando ‘exec <comando>’ , aparte de una serie de lindezas sobre redireccionamientos cuyo ámbito queda fuera de éste manual , reemplaza el proceso de la shell en cuestión con el del comando , el cual debe s er un programa ó otra shell-script. Las implicaciones que ésto tiene son que no se vuelve de dicha ejecución. Veamoslo , para no perder la costumbre , con un ejemplo :

Caso 1:

echo "Ejecuto el comando ls"

ls

echo "Estamos de vuelta"

Caso 2:

echo "Ejecuto el comando ls"

exec ls

echo "Estamos de vuelta"

En el caso -1- , la shell actual ejecuta un hijo que es el comando "ls", espera a que termine y vuelve , es decir , sigue ejecutando el echo "Estamos de vuelta". Sin embargo , en el caso -2- ésto no es as&iacu te; ; hacer exec implica que el número de proceso de nuestra shell pasa a ser el del comando "ls" , con lo que no hay regreso posible , y por tanto , el echo "estamos de vuelta" , NUNCA podría ejecutarse.

Por tanto , al ejecutar un nuevo programa desde exec , el número de proceso (PID) no varía al pasar de un proceso a otro.

-Comando exit <código de retorno>.

Como ya hemos visto parcialmente , éste comando efectúa dos acciones:

Termina de inmediato la ejecución del shell-script , regresando al programa padre (que lógicamente podría ser otra shell ó directamente el inductor de comandos).

Devuelve al proceso antes citado un código de retorno , que podremos averiguar mirando la variable -$?- .

Al terminar una shell script , el proceso inmediatamente antes de acabar , recibe una señal 0 , útil en ocasiones para ver por dónde hemos salido usando el comando "trap".

- Funciones.

De manera similar a las utilizadas en lenguajes convencionales , dentro de una shell se pueden especificar funciones y pasarle parámetros. La sintaxis de una función sería :

nombre_funcion()

{

... comandos ...

}

Las variables de entorno de la función son las mismas que las de la propia shell-script ; debemos imaginar que la propia función se halla "incluída" en la porción de código desde donde la inv ocamos . Por tanto , una variable definida en una función queda definida en la shell y viceversa .

La excepción se produce con los parámetros posiciones ; el $1 , $2 .... cambian su sentido dentro de las funciones , en las cuales representan los parámetros con los que se la ha llamado.

Veamos para variar un ejemplo :

# programa de prueba - llamar con parametros

echo "Hola $1"

pinta()

{

echo "Hola en la función $1"

}

pinta "gorgorito"

Veamos el resultado de la ejecución :

# sh prueba "probando"

Hola probando

Hola en la funcion gorgorito

La variable -$1- , dentro del programa toma el valor del primer parámetro (probando) , y dentro de la función , el parámetro que se le ha pasado a la función (gorgorito). Una vez la función termina , e l $1 vale lo mismo que al principio.

La función nos puede devolver códigos de retorno utilizando la cláusula "return <codigo de error>".

- Ejecución en segundo plano : & , wait y nohup.

Si un comando en la shell termina en un umpresand -&- , la shell ejecuta el comando de manera asíncrona , es decir , no espera a que el comando termine .

La sintaxis para ejecutar un comando en segundo plano es :

comando &

Y la shell muestra un numerito por la pantalla , indicativo del número del proceso que se la lanzado. Hay que tener en cuenta que ése proceso es hijo del grupo de procesos actual asociado a nuestro terminal ; significa que si apagamos el terminal ó terminamos la sesión , tal proceso se cortará.

Para esperar a los procesos en segundo plano , empleamos el comando "wait" que hace que la shell espere a que todos sus procesos secundarios terminen.

Siguiendo con lo de antes , hay veces que ejecutamos :

# comando_lentisimo_y_pesadisimo &

Y queremos apagar el terminal e irnos a casa a dormir ; a tal efecto , existe el comando "nohup" (traducción : no cuelgues , es decir , aunque hagas exit ó apagues el terminal , sigue) , que independiza el proces o en segundo plano del grupo de procesos actual con terminal asociado.

Lo que ésto último quiere decir es que UNIX se encarga de ejecutar en otro plano el comando y nosotros quedamos libres de hacer lo que queramos.

Una duda : al ejecutar un comando en background , la salida del programa nos sigue apareciendo en nuestra pantalla , pero si el comando nohup lo independiza , que pasa con la salida ? La respuesta es que dicho comando crea un fichero ll amado "nohup.out" en el directorio desde donde se ha lanzado , que coniene toda la salida , tanto normal como de error del comando.

Ejemplo sobre cómo lanzar comando_lentisimo_y_pesadisimo :

# nohup comando_lentisimo_y_pesadisimo &

Sending output to nohup.out

12345

#

El PID es 12345 , y la salida del comando la tendremos en el fichero "nohup.out" , el cual es acumlativo ; si lanzamos dos veces el nohup , tendremos dos salidas en el fichero.

- Comandos a ejecutar en diferido : at , batch y cron.

Estos tres comandos ejecutan comandos en diferido con las siguientes diferencias :

AT lanza comandos una sola vez a una determinada hora.

BATCH lanza comandos una sola vez en el momento de llamarlo.

CRON lanza comandos varias veces a unas determinadas horas , días ó meses.

Estos comandos conviene tenerlos muy en cuenta fundamentalmente cuando es necesario ejecutar regularmente tareas de administración ó de operación. Ejemplos de situaciones donde éstos comandos nos pueden ayuda r son :

- Necesitamos hacer una salva en cinta de determinados ficheros todos los días a las diez de la mañana y los viernes una total a las 10 de la noche = CRON.

- Necesitamos dejar rodando hoy una reconstrucción de ficheros y apagar la máquina cuando termine ( sobre las 3 de la mañana ) , pero nos queremos ir a casa (son ya las 8) =AT

- Necesitamos lanzar una cadena de actualización , pero estan todos los usuarios sacando listados a la vez y la máquina está tumbada = BATCH

-Comando at <cuando> <comando a ejecutar>

Ejecuta , a la hora determinada , el <comando>. Puede ser una shell-script , ó un ejecutable.

Este comando admite la entrada desde un fichero ó bien desde el teclado. Normalmente , le daremos la entrada usando el "here document" de la shell.

El "cuando" admite formas complejas de tiempo. En vez de contar todas , veamos algunos ejemplos que seguro que alguno nos cuadrará :

* Ejecutar la shell "salu2.sh" que felicita a todos los usuarios , pasado mañana a las 4 de la tarde:

# at 4pm + 2 days <<EOF

/usr/yo/salu2.sh

EOF

* Lanzar ahora mismo un listado:

at now + 1 minute <<EOF

"lp -dlaserjet /tmp/balance.txt"

EOF

* Ejecutar una cadena de reindexado de ficheros larguísima y apagar la máquina:

at now + 3 hours <<EOF

"/usr/cadenas/reind.sh 1>/trazas 2>&1 ; shutdown -h now"

EOF

* A las 10 de la mañana del 28 de Diciembre mandar un saludo a todos los usuarios :

at 10am Dec 28 <<EOF

wall "Detectado un virus en este ordenador"

EOF

* A la una de la tarde mañana hacer una salvita :

at 1pm tomorrow <<EOF

/Tutoriales/Salvas/diario.sh

EOF

De la misma manera que el comando nohup , éstos comandos de ejecución en diferido mandan su salida al mail , por lo que hay que ser cuidadoso y redirigir su salida a ficheros personales de traza en evitación de satu rar el directorio /var/mail.

El comando "at" asigna un nombre a cada trabajo encolado , el cual lo podemos usar con opciones para consultar y borrar trabajos :

at -l : lista todos los trabajos en cola , hora y día de lanzamiento de los mismos y usuario.

at -d <trabajo>: borra <trabajo> de la cola.

Ya que el uso indiscriminado de éste comando es potencialmente peligroso , existen dos ficheros que son inspeccionados por el mismo para limitarlo : at.allow y at.deny. (Normalmente residen en /usr/spool/atjobs ó en /var/a t).

at.allow:si existe, solo los usuarios que esten aquí pueden ejecutar el comando "at".

at.deny:si existe, los usuarios que estén aquí no estan autorizados a ejecutar "at".

El "truco" que hay si se desea que todos puedan usar at sin tener que escribirlos en el fichero , es borrar at.allow y dejar sólo at.deny pero vacío.

- Batch .

Ejecuta el comando como en "at" , pero no se le asigna hora ; batch lo ejecutará cuando detecte que el sistema se halla lo suficientemente libre de tareas. En caso que no sea así , se esperará hasta que oc urra tal cosa.

-Cron.

No es un comando ; es un "demonio" , ó proceso que se arranca al encender la máquina y está permanentemente activo. Su misión es inspeccionar cada minuto los ficheros crontabs de los usuarios y ejec utar los comandos que allí se digan a los intervalos horarios que hayamos marcado. Como se acaba se señalar , los crontabs son dependientes de cada usuario.

Se deben seguir los siguientes pasos para modificar , añadir ó borrar un fichero crontab :

1 - Sacarlo a fichero usando el comando "crontab -l >/tmp/mio" , por ejemplo.

2 - Modificarlo con un editor de acuerdo a las instrucciones de formato que se explican a continuación.

3 - Registrar el nuevo fichero mediante el comando "crontab /tmp/mio" , por ejemplo.

mira cada minuto el directorio /var/spool/crontabs y ejecuta los comandos

crontab .

El formato del fichero es el siguiente :

#minutos horas dia mes mes dia-semana comando ( # = comentario )

minutos : de 0 a 59.

horas : de 0 a 23.

dia del mes : de 0 a 31.

mes : de 0 a 12.

día semana : de 0 a 6 ( 0 = domingo , 1 = lunes ...)

Aparte de la especificación normal , pueden utilizarse listas , es decir , rangos de valores de acuerdo con las siguientes reglas :

8-11 : Rango desde las 8 hasta las 11 ambas inclusive.

8,9,10,11 : Igual que antes ; desde las 8 hasta las 11.

Si queremos incrementar en saltos diferentes de la unidad , podemos escribir la barra "/" :

0-8/2 : Desde las 12 hasta las 8 cada 2 horas. Equivale a 0,2,4,6,8 .

El asterisco significa "todas" ó "todo". Por tanto :

*/2 : Cada dos horas.

Ejemplos más evidentes :

# ejecutar una salvita todos los dias 5 minutos despues de las 12 de la noche :

5 0 * * * /Tutoriales/salvas/diaria.sh 1>>/Tutoriales/salvas/log 2>&1

# ejecutar a las 2:15pm el primer dia de cada mes:

15 14 1 * * /Tutoriales/salvas/mensual.sh 1>/dev/null 2>&1

# ejecutar de lunes a viernes a las diez de la noche - apagar la maquina que es muy tarde

0 22 * * 1-5 shutdown -h now 1>/dev/null 2>&1

# ejecutar algo cada minuto

* * * * * /Tutoriales/cosas/espia.sh

4 TRATAMIENTO DE FICHEROS.

Comando :wc <opciones> <nombre-archivo>

Misión: cuenta lineas,palabras o caracteres de un fichero.

opciones:

-l:lineas

-c:letras

-w:palabras

Ejemplo:

l=`wc -l /etc/passwd` ; echo "Hay $l usuarios registrados en este equipo"

En la variable $l tendríamos el número de líneas del fichero /etc/passwd.

Comando: tr <opciones> 'caracteres orig' 'caracteres destino' < nombre-archivo

Misión: sustituye globalmente un caracter por otro .

Ejemplo:

tr '[a-z]' '[A-Z]' < /etc/passwd >/tmp/passwd.MAYUSCULAS

Pasa el fichero de entrada a mayúsculas.

Comando: cut <opciones> <nombre de archivo>

Misión: corta texto a través del número absoluto de columna o el número relativo de

campo.

Opciones:

-c:numero absoluto de columna

-f:numero de campo.

-d:delimitador de campo.

Especificación de números de columna.

1,3,10 : primera , tercera y decima columnas.

1-3 : de la primera a la tercera columna.

1-3,8 : de la primera a la tercera y la octava.

-5 : de la primera a la quinta columna

5- : de la quinta a la última.

Ejemplo :

cut -d"." -f1 /etc/passwd

lista sólamente los nombres del fichero /etc/passwd , cortando por el delimitador ‘:’ .

Comando: paste.

Misión:

Comando : split <-numero de lineas de los ficheros> <fichero>

Misión: divide <fichero> en n ficheros de <num.lin> cada uno. Si no se indica el

numero de lineas , se consideran 1000.

los ficheros que genera se llaman xaa , xab , xac ...

Ejemplo:

$ split gordo

$ ls

gordo xaa xab xac xad xae xaf xag

Ha partido el fichero "gordo" en ficheros más pequeños , de 1000 líneas cada uno , denominados "xaa" ,"xab" ..... Si borramos el fichero "gordo" , podríamos volver a ge nerarlo con el comando siguiente:

$ cat xaa xab xac xae xaf xag > gordo

Comando: sort <opciones> <indicador de campo> <fichero>

Misión: ordena un fichero de acuerdo a una secuencia de odenacion determinada.

Ejemplo

dado un fichero con:

codigo nombre ciudad telefono

$ sort fichero # ordena por todos los campos

$ sort +1 fichero # ordena a partir del campo 1 (nombre ; codigo es el 0)

$ sort +2n fichero # ordena por nombre , en secuencia invertida.

$ sort +2n -t":" fichero # igual que antes , pero suponiendo que el separador es ":".

Comando: grep <cadena a buscar> <fichero>

Misión: buscar apariciones de palabras ó textos en ficheros.

Ejemplo:

$ grep root /etc/passwd # busca las líneas que contienen "root" en el fichero.

root:Ajiou42s:0:1:/:/bin/sh

Otro:

$ ps -e | grep -v constty # busca qué procesos no ruedan en la consola

( ...... )

La familia de grep , así como otros comandos tales como de (editor de líneas), sed (editor batch) y vi , manejan expresiones regulares para la búsqueda de secuencias de caracteres. Una expresión regular es un a expresión que especifica una secuencia de caracteres. Un ejemplo de ésto es el comando : ls -l | grep "^d" ; el "^d" es una expresión regular que equivale a decir "si la letra -d- está al principio de la línea" ; la construcción anterior nos lista sólo los directorios.

Las expresiones regulares conviene esconderlas de la shell encerrándolas entre comillas.

Algunos montajes de expresiones regulares son :

<.> (Punto) :cualquier carácter distinto al del fin de línea.

[abc] :la letra a , la b ó la c.

[^abc] :cualquier letra distinta a a , b ó c.

[a-z] :cualquier letra de la -a- a la -z- .

Una letra seguida de un asterisco -*- equivale a cero ó más apariciones de la letra. Por tanto , la expresión .* equivale a decir "cualquier cosa". Por tanto, el comando :

ls -l | grep ‘\.sh.*"

lista todos los ficheros que terminen en .sh mas los terminados en .sh<otras letras> . Nótese que el punto inicial lo hemos desprovisto de su significado "escapándolo" con un backslash -\- .

^ : al principio de una expresión regular equivale a "desde el principio de la línea".

$ : al final de una expresión regular equivale a "hasta el final de la línea".

Ejemplos de ésto :

ls -l | grep ‘\.sh$’ : saca los ficheros que SOLO acaben en .sh

Este tema se complica todo lo que se quiera . Veamos algunas expresiones regulares bastante usadas en comandos tipo sed ( que veremos más tarde ) para percatarse de ello :

[^ ] : cualquier letra diferente de espacio.

[^ ]* : una palabra cualquiera (varias letras no blancas).

[^ ]* * : una palabra seguida de un número incierto de blancos.

^[^ ]* * : la primera palabra de la línea y a todos los blancos que la siguen.

Comando: diff <fichero1> <fichero2>

Misión: Encuentra las diferencias entre dos ficheros.

Ejemplo:

$ cat nombres1

jose

juan

roberto

$ cat nombres2

jose

roberto

$ diff nombres1 nombres2

2d1

< juan

Comando: join <fichero1> <fichero2>

Misión: mezcla ficheros clasificados

$ cat uno

antonio alperchines,5

juan seneca,32

maria oxigeno,45

pablo isaac peral,54

$ cat dos

antonio madrid

juan segovia

maria avila

pablo guadalajara

$ join uno dos

antonio alperchines,5 madrid

juan seneca,32 segovia

maria oxigeno,45 avila

pablo isaac peral,54 guadalajara

Comando: fold <-ancho-en-columnas> <fichero>

Misión: pasar palabras automáticamente a la línea siguiente. En el caso de tener un texto con líneas de más de 80 caracteres , al imprimirlo queda truncado. Usando éste comando , cualquie r texto que sobrepase el ancho establecido se pasa a la línea inferior.

Ejemplo:

fold -80 carta.txt | lp

Comando: sed ‘comandos de sed’ <ficheros>

Misión efectúa cambios en ‘fichero’ , enviando el resultado por la salida estándar. Pueden guardarse los resultados de éstas operaciones en un fichero como siempre , redireccionando la salida , tal que - sed ‘expresion’ fichero >/tmp/salida -.

Utilizaremos sed normalmente cuando sea necesario hacer cambios en ficheros de texto ; por ejemplo , nos puede valer para cambiar determinada variable en una serie de ficheros de profile de usuario , etc.

La explicación completa de éste comando exigiría mucho detalle ; veamos sólamente algunos ejemplos de operaciones con sed :

* Cambiar , en el fichero /Tutoriales/pepito/.profile , la expresión TERM=vt100 por TERM=vt220 . Usamos el comando ‘s/expresion_a_buscar/expresion_a_cambiar/g’ (s=search,g=global) :

sed ‘s/TERM=vt100/TERM=vt220/g’ /Tutoriales/pepito/.profile >/tmp/j && mv /tmp/j /Tutoriales/pepito/.profile

(si el comando ha sido OK , entonces movemos el /tmp/j).

* Meter tres blancos delante de todas las líneas del fichero /tmp/script.sh :

sed ‘s/^/ /’ /tmp/script.sh >/tmp/j && mv /tmp/j /tmp/script.sh

(el ^ identifica el principio de cada línea).

* (mas raro): Cepillarse todos los ficheros de un directorio :

ls | sed ‘s/^/rm -f /’ | sh

(del ls sale el fichero ; el sed le pone delante "rm -f" y el sh lo ejecuta.
[editar]

5 opiniones

Mm mas omenos.

Pues la verdad esta muy bien pero me gustaria mas cosas acerca de la historia de unix lo agradeceria mucho gracias.
Unix.

Bueno.
Bueno !!!.

Me parecio bastante bien puesto que nunca habia trabajado con este s. O, y en verdad esta bastante bueno para iniciar en el.
Buscaba.

Me parecio exelente pero almenos lo que yo pedi al buscador por ser en este momento mi prioridad, una tabla comparativa de los 4 diferentes tipos de shell.
Mi opinion es.

K esta bien y k esta bien la información.

Cursos gratis relacionados con 'Curso de Unix de la A a la Z'

Este es un curso tremendamente completo, guiado y con ejemplos y prácticas pensadas para convertirlo... Más »
Práctico y completo curso de hacking.
La meta de este curso es el aprendizaje de métodos en programación, tanto en teoría... Más »
En este glosario, lo primero que se ha de definir es la palabra HACKER ya... Más »
Linux es una gran herramienta, la uso desde hace años y se ha convertido en... Más »

Autor y licencia de 'Curso de Unix de la A a la Z'


Curso gratis de Publispain. Extraido de: http://www.publispain.com CopyLeft
Este contenido ha sido recopilado por el equipo de Wikilearning. Todo el contenido recopilado se ha obtenido respetando y comunicando en nuestro site la licencia de cada fuente.
Wikilearning tiene permiso expreso por escrito de los autores para publicar los contenidos que ha extraído de otras webs, incluyendo su uso comercial.