Programación del Shell LinuxAquí tenemos un libro libre y completo sobre ShellLa sed del "conocimiento libre" es muy bienvenida. |
Comandos Shell Script |
![]() |
|
Home |
Artículos ![]() ![]() |
Comprar el libroChangelogs |
|
Conversación de Bar - Parte III- Mozo, traiga dos "choppes" por favor, que hoy voy a tener que hablar mucho. Trabajando con cadenasPor el título de arriba no pienses que te voy a enseñar a ser carcelero! Me estoy refiriendo a cadenas de caracteres! El Comando cut (que no es la central única de trabajadores)
Primero te quiero mostrar, de forma eminentemente práctica, una instrucción simple de usar y muy útil: el comando El comando
|
Principales Opciones del comando tr | |
---|---|
-d | Elimina del archivo los caracteres de la cadena1 |
Opción | Significado |
-s | Comprime n coincidencias de la cadena1 en sólo una |
tr
Primero te voy a dar un ejemplo bien bobo:
O sea, cambié todas las coincidencias de la letra o
por la letra a
.
Suponte que en un determinado punto de mi script, pido al operador que teclee s
o n
(si o no), y guardo su respuesta en la variable $Resp
. El contenido de $Resp
puede estar con letras mayúsculas o minúsculas, y de esta forma tendría que hacer diversos tests para saber si la respuesta dada fue S
, s
, N
o n
. Entonces lo mejor es hacer:
y despues de ejecutar este comando tendría la seguridad de que el contenido de $Resp
seria un s
o un n
.
Si mi archivo ArchEnt
está todo escrito con letras mayúsculas y deseo pasarlas para minúsculas hago:
Observa que en este caso usé la notación A-Z
para no tener que escribir ABCD...YZ
. Otro tipo de notación que puede ser usada son las escape sequences (preferiría escribir en español, pero en este caso como lo traduciría? Secuencias de escape? Medio sin sentido, no te parece? Pero continuemos...) que también son reconocidas por otros comandos y también en lenguaje C, y cuyo significado verás a continuación:
Escape Sequences | ||
---|---|---|
\\ | Una barra invertida | \0134 |
Secuencia | Significado | Octal |
\t | Tabulación | \011 |
\n | Nueva línea |
\012 |
\v | Tabulación Vertical | \013 |
\f | Nueva Página | \014 |
\r | Início de línea <^M> | \015 |
tr
Dejame contarte un "causo": un alumno que estaba enojado conmigo, decidió complicarme la vida y en un ejercicio práctico que pasé para ser hecho en el computador, y que valía para nota, me entregó el script con todos los comandos separados por punto y coma (recuerdas que te dije que el punto y coma servía para separar diversos comandos en una misma línea?).
Te voy a dar un ejemplo simplificado e idiota de un "chorizo" así:
Yo ejecutaba el programa y se ejecutaba así:
Pero nota de prueba es cosa seria (y billete de dólar todavia más ) entonces, para entender lo que el alumno habia hecho, lo llamé y delante suyo ejecuté el siguiente comando:
El alumno se quedó muy triste, porque en 2 o 3 segundos le deshice la broma en la había perdido varias horas.
Ahora fíjate bien! Si yo tuviera una máquina con Unix, habria hecho lo siguiente:
tr
Observa ahora la diferencia entre los dos comandos date
: el que hice hoy y el otro que fue ejecutado hace dos semanas:
Para ver la hora debería hacer:
Sin embargo, dos semanas antes ocurriría lo siguiente:
Ahora observa porqué:
Como puedes notar, existen 2 caracteres en blanco antes del 5
(día), esto lo confunde todo porque el tercer pedazo está vacio y el cuarto es el día (5
). Entonces lo ideal sería comprimir los espacios en blanco sucesivos en solamente un espacio, para poder tratar las dos cadenas resultantes del comando date
de la misma forma, y eso se hace así:
Como puedes ver, no existen los dos espacios, Entonces ahora podria cortar:
Viste como el Shell ya está solucionando problemas! Observa este archivo que fue bajado de una máquina con aquél sistema operativo que sufre de todos los vírus:
y ahora te quiero dar dos consejos:
-v
del cat
muestra los caracteres de control invisibles, con la notación ^L
, donde ^
es la tecla control y L
es la respectiva letra. La opción -e
muestra el final de la línea como un signo de pesos ($
).
\r
) y un line-feed (\n
). En Linux sin embargo, el final del registro tiene solamente el line-feed.
Vamos entonces a limpiar este archivo.
Ahora vamos a ver lo que pasó:
Bien, la opción -d
del tr
retira los caracteres especificados de todo el archivo. De esta forma retiré los caracteres no deseados, grabandolo en un archivo de trabajo temporal y posteriormente lo renombré con su nombre original.
Obs: En Unix debería hacer:
ftp
fue hecho de modo binario (o image
), o sea, sin la interpretación del texto. Si antes de la transmisión del archivo hubiera sido estipulada la opción ascii
del ftp
, esto no habría ocurrido.
- Mira, después de este consejo, estoy comenzando a disfrutar de ese tal Shell, pero todavia hay muchas cosas que no consigo hacer.
- Claro!, si hasta aqui no te hablé casi nada sobre programación en Shell, tenemos muchas cosas aun por avanzar, sin embargo, con lo que aprendiste, ya te da para resolver muchos problemas, hasta que tú adquieras el “modo Shell de pensar”. Serías capaz de hacer un script para decirme quienes son las personas que están “logadas” desde hace más de un dia en tu servidor?
- Claro que no! Para eso seria necesario que conociera los comandos condicionales que todavia no me explicaste como funcionan.
- Dejame intentar cambiar un poco tu lógica y atraerla hacia el “modo Shell de pensar”, pero antes es mejor tomar un chope... Chico!, traeme otros dos...
- Ahora que ya moje el gaznate, vamos a resolver el problema que te propuse. Presta atención a como funciona el comando who:
Y mira también el date
:
Ves que el mes y el dia están en el mismo formato en ambos comandos?
date
hacia portugués, o hacia cualquier otro idioma que quieras.
Entonces, si en algún registro del who
no encuentro la fecha de hoy, significa que el individuo está "logado" hace más de un día, ya que él no puede haberse "logado" mañana... Vamos a guardar el pedazo que importa de la fecha de hoy para buscarla en la salida del who
:
Aquí usé la construcción $(...)
, para dar prioridad a la ejecución de los comandos antes de atribuir a su salida a la variable $Fecha
. Vamos a ver si funcionó:
Muy bien! Ahora, lo que tenemos que hacer es buscar con el comando who
los registros que no poseen esta fecha.
- Ah! Me parece que estoy entendiendo! Ahora que mencionaste lo de buscar, se me ocurrió el comando grep
, acerté?
- Correctísimo! Solo que tengo que usar el grep
con aquella opción que solamente lista los registros en los quales no encontró la cadena. Te acuerdas que opción es esa?
- Claro, es la opción -v
...
- Eso mismo! Estás quedando un lujo! Entonces vamos a ver:
- Y si quisiera un poco mas de adornos,haría así:
- Te diste cuenta? No fue necesario usar ningún comando condicional, porque además nuestro comando condicional más usado, el famoso if
, no verifica condición sino instrucciones, como veremos ahora.
Observa las líneas de comando que siguen:
- y que hace ese $?
por ahí? Comenzando por pesos ($
) parece ser una variable, correcto?
- Si, es una variable que contiene el código de salida de la última instrucción ejecutada. Te puedo garantizar que si esta instrucción fué bien ejecutada, $? tendrá el valor cero, en caso contrario su valor será diferente de cero.
Lo que nuestro comando condicional if
hace es testar la variable $?
. Veamos entonces a ver su sintaxis:
if cmd then cmd1 cmd2 cmdn else cmd3 cmd4 cmdm fi
o sea: en caso que el comando cmd
haya sido ejecutado con éxito, los comandos del bloque del then
(cmd1
, cmd2
y cmdn
) serán ejecutados, en caso contrario, los comandos ejecutados serán los del bloque opcional del else
(cmd3
, cmd4
y cmdm
), terminando con un fi
.
Vamos a ver en la prática como funciona eso usando un scriptisiño que sirve para incluir usuários en el /etc/passwd
:
Nota que el if
está verificando diretamente el comando grep
y ésta es su finalidad. En caso de que el if
sea exitoso, o sea, el usuário (cuyo nombre está en $1
) fuera encontrado en /etc/passwd
, los comandos del bloque del then
serán ejecutados (en este ejemplo es solamente el echo
) y en el caso contrario, las instrucciones del bloque del else
son las que serán ejecutadas, entonces un nuevo if
verifica si el comando useradd
fué bien ejecutado , creando el registro del usuario en /etc/passwd
, o no, y es entonces cuando dará el mensaje de error.
Veamos su ejecución, primero pasando un usuario ya existente:
Como ya vimos diversas veces, pero siempre es bueno insistir en el tema para que te quede claro, en el ejemplo anterior surgió una línea no deseada, esta es la salida del comando grep
. Para evitar que eso pase, debemos desviar la salida de esta instrucción para /dev/null
, quedando así:
Ahora vamos a verificarlo, pero como usuario normal (no root):
Epa!, aquél error no tenia que pasar! Para evitar que eso suceda debemos mandar también la salida de error (strerr, te acuerdas?) del useradd
hacia /dev/null
, quedando la versión final así:
Después de estas alteraciones y de hacer un su –
(volverme root) veamos su comportamiento:
Y nuevamente:
Recuerdas que te dije que a lo largo de nuestras conversaciones y "choppes" nuestros programas irían mejorando? Entonces veamos ahora como podríamos mejorar nuestro programa para incluir músicas:
Como viste, es una pequeña evolución de la versión anterior, de forma que, antes de incluir un registro (que con la versión anterior podría ser duplicado), verificamos si el registro comenzaba (^
) y terminaba ($
) igual al parámetro pasado ($1
). El uso del circunflejo (^
) en el inicio de la cadena y el pesos ($
) en el fin, son para verificar si el parámetro pasado (el álbum y sus datos) son exactamente iguales a algún registro anteriormente incluído y no unicamente igual a un pedazo de alguno de los registros.
Vamos a ejecutarlo pasando un álbum ya anteriormente incluído:
Y ahora uno no incluído:
- Como viste, el programa mejoró un poquito, pero todavia no está listo. A medida que te vaya enseñando a programar en shell, nuestra CDteca va a ir quedando cada vez mejor.
- Entendí todo lo que me explicaste, pero todavia no sé como hacer un if
para verificar condiciones, o sea el uso normal del comando.
- Mira, para eso existe el comando test
, él es quien verifica condiciones. El comando if
verifica el comando test
. Pero eso está medio confuso y como ya hablé mucho, estoy necesitando unos "choppes" para mojar las palabras. Vamos a parar por aqui y la próxima vez te explico claramente el uso del test
y de diversas otras sintáxis del if
.
- Estamos de acuerdo entonces! Me parece bien porque yo tambiém estoy quedando tonto y así aprovecho para practicar esa cantidad de cosas de las cuales me hablaste hoy .
- Para memorizar lo que aprendiste, trata de hacer un scriptiziño para informar si un determinado usuario, que será pasado como parámetro está logado (ajjjhh!) o no.
- Chico,dos "choppes" más por favor...
Y no te olvides, cualquer duda o falta de compañia para tomar una cerveza o hasta para hablar mal de los políticos lo único que tienes que hacer es mandarme un e-mail para julio.neves@gmail.com. Voy aprovechar tambiém para mandar mi aviso publicitario: puedes decirle a los amigos que quien quiera hacer un curso nota diez de programación en Shell que mande un e-mail para julio.neves@uniriotec.br para informarse.
Gracias y hasta la próxima
-- HumbertoPina - 04 Oct 2006