64
Programación en SHELL ( Bash ) ¿ Que es una shell ? El shell de Unix o también shell, es el termino usado en informática para referirse a un interprete de comandos. Los comandos que aportan los intérpretes, pueden usarse a modo de guión si se escriben en ficheros ejecutables denominados shell-scripts, de este modo, cuando el usuario necesita hacer uso de varios comandos o combinados de comandos con herramientas, escribe en un fichero de texto marcado como ejecutable, las operaciones que posteriormente, línea por línea, el intérprete traducirá al núcleo para que las realice. Sin ser un shell estrictamente un lenguaje de programación, al proceso de crear scripts de shell se le denomina programación shell o en inglés, shell programming o shell scripting. Los usuarios de Unix y similares, pueden elegir entre distintos shells (programa que se debería ejecutar cuando inician la sesión, bash, ash, csh, zsh, ksh, tcsh). El término shell también hace referencia a un programa particular, tal como el Bourne shell, sh. El Bourne shell fue el shell usado en las primeras versiones de Unix y se convirtió en un estándar; todos los sistemas similares a Unix tienen al menos un shell compatible con el Bourne shell. El programa Bourne shell se encuentra dentro de la jerarquía de archivos de Unix en /bin/sh. En algunos sistemas, tal como BSD, /bin/sh es un Bourne shell o un equivalente, pero en otros sistemas como muchas distribuciones de Linux, /bin/sh es un enlace simbólico a un shell compatible con más características (como Bash). POSIX especifica su shell estándar como un subconjunto estricto del Korn shell. Primeros pasos Uno de los primeros pasos es saber que shell (interprete de comando estamos usando). $ echo $SHELL /bin/bash Las variables por convención se utiliza en mayúsculas y las forma de obtener el contenido de la variable o mejor dicho su valor es poniendo el símbolo $. Si queremos saber la versión de nuestro interprete de comandos en este caso bash ejecutamos el siguiente comando : $ echo $BASH_VERSION 4.1.5(1)-release Para conocer todos los interpretes de comandos que tenemos veremos que se guardan dentro de un archivo llamado shells. $ cat /etc/shells /bin/csh /bin/sh /bin/ksh /bin/tcsh /bin/dash /bin/bash

Programacion Swift

Embed Size (px)

Citation preview

  • Programacin en SHELL ( Bash )

    Que es una shell ?

    El shell de Unix o tambin shell, es el termino usado en informtica para referirse a un interprete de comandos. Los comandos que aportan los intrpretes, pueden usarse a modo de guin si se escriben en ficheros ejecutables denominados shell-scripts, de este modo, cuando el usuario necesita hacer uso de varios comandos o combinados de comandos con herramientas, escribe en un fichero de texto marcado como ejecutable, las operaciones que posteriormente, lnea por lnea, el intrprete traducir al ncleo para que las realice.Sin ser un shell estrictamente un lenguaje de programacin, al proceso de crear scripts de shell se le denomina programacin shell o en ingls, shell programming o shell scripting.Los usuarios de Unix y similares, pueden elegir entre distintos shells (programa que se debera ejecutar cuando inician la sesin, bash, ash, csh, zsh, ksh, tcsh).

    El trmino shell tambin hace referencia a un programa particular, tal como el Bourne shell, sh. El Bourne shell fue el shell usado en las primeras versiones de Unix y se convirti en un estndar; todos los sistemas similares a Unix tienen al menos un shell compatible con el Bourne shell. El programa Bourne shell se encuentra dentro de la jerarqua de archivos de Unix en /bin/sh. En algunos sistemas, tal como BSD, /bin/sh es un Bourne shell o un equivalente, pero en otros sistemas como muchas distribuciones de Linux, /bin/sh es un enlace simblico a un shell compatible con ms caractersticas (como Bash). POSIX especifica su shell estndar como un subconjunto estricto del Korn shell.

    Primeros pasos

    Uno de los primeros pasos es saber que shell (interprete de comando estamos usando).

    $ echo $SHELL/bin/bash

    Las variables por convencin se utiliza en maysculas y las forma de obtener el contenido de la variable o mejor dicho su valor es poniendo el smbolo $.

    Si queremos saber la versin de nuestro interprete de comandos en este caso bash ejecutamos el siguiente comando :

    $ echo $BASH_VERSION4.1.5(1)-release

    Para conocer todos los interpretes de comandos que tenemos veremos que se guardan dentro de un archivo llamado shells.

    $ cat /etc/shells/bin/csh/bin/sh/bin/ksh/bin/tcsh/bin/dash/bin/bash

  • Si queremos cambiar nuestro shell por defecto a bash ejecutamos el siguiente comando y luego volvemos a loguearno para que tome la nueva configuracin.

    $ chsh -s /bin/bash

    Manejo de comodines

    Los comodines de bsqueda son signos o smbolos que nos ayudarn a la hora de encontrar algn archivo en nuestro ordenador. Donde mas lo podemos llegar a utilizar es con el comando ls.

    $ ls /bin/bash

    Ac tenemos una tabla con los distintos comodines y su explicacin.

    Comodn Descripcin

    ? Uno o slo un carcter.

    * Cero o ms caracteres.

    [conjunto] Uno los caracteres de conjunto.

    [!conjunto] Un carcter que no este en conjunto.

    Ejemplo de usos :

    $ ls *.txt

    En el ejemplo anterior me trae cualquier archivo que tenga como extensin txt.

    $ ls /bin/l?/bin/ln /bin/ls

    El tercer comodn permite indicar un conjunto de caracteres que son vlidos. Por ejemplo l[eno]* encontrara el fichero less lesssecho lessfile lesskey lesspipe ln loadkeys login no traira liss. Es decir como primer letra si o si l a continuacin puede ser e, n o o y luego como bien dijimos el comodn (*) representa cero o ms caracteres realiza una distributiva.

    $ ls /bin/l[eno]*/bin/less /bin/lessecho /bin/lessfile /bin/lesskey /bin/lesspipe /bin/ln /bin/loadkeys /bin/login

    El comod n tilde

    Este comodn es ~ que se utiliza para referirse al home de los usuarios, por ejemplo ~pablo se refiere a /home/pablo.

    $ ls -a ~pablo./ ../ .bash_logout .bash_profile .bashrc

    El comod n llaves

    Este comodn a comparacin de los otros, no estudia el nombre de los ficheros existentes en disco para nada, simplemente expande una palabra por cada una de las cadenas de caracteres que contiene, por ejemplo :

  • $ echo c{ami,ontamina,}oncamion cantaminaon con

    Lo que realiza es una distribucin c->ami->on, c->ontaminaon y c->con, al poner ,} lo que hace es poder formar la palabra con es decir como luego de la , no hay nada puede formar otra palabra con on.

    Veamos un ejemplo mas complejo que aade mas llaves :

    $ echo c{a{mi,nt}a,ose}rcaminar cantar coser

    Siempre combina c->a y luego con {mi,nt} luego con a y la r y por ultimo combina c->ose->r

    Se puede usar dos puntos (..) para hacer algo similar a lo que hacen los corchetes es decir indicar un rango. Por ejemplo :

    $ echo l{a..j}la lb lc ld le lf lg lh li lj

    Las llaves deben tener al menos dos cadenas, el siguiente ejemplo vemos que esto no sucede.

    $ echo ca{a}saca{a}sa

    Comodines extendidos

    Bash permite usar un conjunto de comodines extendidos, pero para poder usarlos debemos de activar la opcin ext_glob de Bash.

    Para fijar estos valores usamos el comando shopt (shell option), si ejecutamos el comando shopt veremos la lista de variables que podemos modificar.

    $ shoptautocd offcdable_vars offcdspell offcheckhash offcheckjobs offcheckwinsize oncmdhist oncompat31 offcompat32 offcompat40 offdirspell offdotglob offexecfail offexpand_aliases onextdebug offextglob onextquote onfailglob offforce_fignore onglobstar offgnu_errfmt off

  • histappend onhistreedit offhistverify offhostcomplete offhuponexit offinteractive_comments onlithist offlogin_shell offmailwarn offno_empty_cmd_completion offnocaseglob offnocasematch offnullglob offprogcomp onpromptvars onrestricted_shell offshift_verbose offsourcepath onxpg_echo off

    Todas estas variables son booleanas que contienen el valor on/off, para activarlo usamos el comando shopt -s opcion y para desactivarlo shopt -u opcion.

    Vemos en la tabla algunas de esa opciones con mayor detalle de lo que hace :

    Opcin Descripcin

    cdable_vars Permite que cd use los valores de las variables como nombres de directorios.

    cdspell Ignora pequeos errores en los cambios de directorio con cd. Slo en la ejecucin interactiva.

    cmdhist Guarda los comandos que hemos escrito en varias lneas en una sola lnea del historial.

    dotglob Incluye en la expansin de comodines los ficheros que empiezan por (.).

    expand_aliases Expande un alias cuando lo ejecuta.

    extglob Utiliza extensiones de los comodines.

    failglob Si falla la expansin de un comodn porque no encuentra nada falla el comando (como hace el C shell).

    force_fignore Los sufijos especificados en la variable de entorno FIGNORE no se usan para completar palabras con tabulador.

    hostcomplete Se intenta completar nombres de host al pulsar tabulador cuando la palabra contiene una @.

    interactive_comments Permite que dentro de un comando de sesin interactiva haya comentarios (precedidos por #).

    login_shell Variable de slo lectura que indica si Bash ha sido lanzado como un shell de login.

    nocaseglob Indica si los comodines expanden sin sensibilidad a maysculas/minsculas. No confundir con la variable completion-ignore-case de inputrc que lo que haca era expandir con tabuladores.

    nullglob Hace que cuando un patrn no encuentra ficheros, se expandan por la cadena vaca en vez de por el patrn sin expandir.

    sourcepath Hace que el comando interno source busque el argumento en los directorios que indique PATH.

  • Ejemplo :

    $ export DOC=/usr/share/doc$ shopt -s cdable_vars$ cd DOC

    La opcin cdable_vars permite que el comando cd pueda utilizar variables como nombres de directorios. Observamos que DOC al utilizarlo con el comando cd no va precedido por $.

    $ shopt -s extglob

    Con esta opcin podemos utilizar uno de estos cinco nuevos tipos de patrones:

    ?(pattern-list) Cero o una ocurrencia de pattern-list.

    *(pattern-list) Cero o ms ocurrencias de pattern-list.

    +(pattern-list) Una o ms ocurrencias de pattern-list.

    @(pattern-list) Exactamente uno de los patrones de la lista.

    !(pattern-list) Cualquier cosa excepto uno de los patrones de la lista.

    $ ls -l /bin/l?-rwxr-xr-x 1 root root 48920 abr 28 2010 /bin/ln-rwxr-xr-x 1 root root 108008 abr 28 2010 /bin/ls

    Ejemplo donde solo listo que coincida con 0 o 9.

    $ touch carta{0..9}.txt$ ls carta+([0..9]).txtcarta0.txt carta9.txt

    Ejemplo donde listo el rango de 0 a 9.

    $ touch carta{0..9}.txt$ ls carta+([0-9]).txtcarta0.txt carta1.txt carta2.txt carta3.txt carta4.txt carta5.txt carta6.txt carta7.txt carta8.txt carta9.txt

    Si queremos buscar los archivos que solo tengan extensin .c, .h y .o realizamos lo siguiente :

    $ touch ejemplo{c,h,o,cpp}.txt$ ls *.[cho]ejemplo.c ejemplo.h ejemplo.o

    Vemos que en el ejemplo anterior solamente me trae las extensiones que contengan solo un carcter (*.c, *.h y *.o), el corchetes [] slo permite acepta un carcter. Si quiero traer los que tengan extensin .cpp no se podr. En cambio con el siguiente ejemplo si podemos :

    $ touch ejemplo{c,h,o,cpp}.txt$ ls *.@(c|o|h|cpp)ejemplo.c ejemplo.cpp ejemplo.h ejemplo.o

    Con el pipe (|) realiza un or (o) que coincida con algunos de los patrones correspondientes lo que me permite aadir patrones.

  • El ejemplo anterior es equivalente a :

    $ ls @(*.c|*.o|*.h|*.cpp)ejemplo.c ejemplo.cpp ejemplo.h ejemplo.o

    Si quiero listar lo que no sea con extensin *.c, *.o, *.h y *.cpp realizo la muestra con el patrn !

    $ ls !(*.c|*.o|*.h|*.cpp)carta0.txt carta1.txt carta2.txt carta3.txt carta4.txt carta5.txt carta6.txt carta7.txt carta8.txt carta9.txt

    Si quiero borrar todos los archivos excepto los que empiezan con papel[0-9].txt realizo lo siguiente :

    $ touch carta{0..9}.txt$ touch papel{0..9}.txt$ rm -v !(papel+([0-9])).txtcarta0.txt borradocarta1.txt borradocarta2.txt borradocarta3.txt borradocarta4.txt borradocarta5.txt borradocarta6.txt borradocarta7.txt borradocarta8.txt borradocarta9.txt borrado

    Comandos internos de Bash

    Bash siempre busca los programas que ejecutamos en los directorios indicados en la variable de entorno $PATH, pero hay ciertos comandos internos de bash que no corresponde a ningn archivo del disco, algunos de estos comandos son cd, chdir, alias, set o export, etc.

    Para saber los comandos que tenemos en bash ejecutamos help.

    $ help$ help aliasalias: alias [-p] [name[=value] ... ] Define o muestra aliases. `alias' sin argumentos muestra la lista de aliases en la forma reutilizable `alias NOMBRE=VALOR' en la salida estndar. De otra manera, se define un alias por cada NOMBRE cuyo VALOR se proporcione. Un espacio final en VALOR causa que se revise la siguiente palabra para sustitucin de alias cuando se expande el alias. Opciones: -p Muestra todos los aliases definidos en un formato reusable Estado de salida: alias devuelve verdadero a menos que se de un NOMBRE para el cual no se haya definido ningn alias.

  • Caracteres especiales y entrecomillado

    Los caracteres , |, &, *, ?, ~, [, ], {, } son ejemplos de caracteres especiales de Bash que ya hemos visto en captulos anteriores.

    Carcter Descripcin

    ~ Directorio home.

    ` Sustitucin de comando.

    # Comentario.

    $ Variable.

    & Proceso en background.

    ; Separador de directorios.

    * Comodn 0 a n carcter.? Comodn de un slo carcter.

    / Separdor de directorios.

    ( Empezar un subshell.

    ) Terminar un subshell.

    \ Carcter de escape.

    < Redirigir la entrada.

    > Redirigir la salida.

    | Pipe.

    [ Empieza conjunto de caracteres comodn.

    ] Acaba conjunto de caracteres comodn.

    { Empieza un bloque de comando.

    } Acaba un bloque de comando.

    ' Entrecomillado fuerte.

    Entrecomillado dbil.

    ! No lgico de cdigo de terminacin.

    Caracteres de escape

    Otra forma de cambiar el significado de un carcter de escape es precederlo por \, que es lo que se llama el carcter de escape.

    Por ejemplo :

    $ echo 2\*\3\>5 es una expresion cierta2*3>5 es una expresion cierta

    Donde hemos puesto el carcter de escape a los caracteres especiales para que Bash no los interprete.

    Tambin lo usamos para que poder usar los espacios a los nombres de ficheros, ya que el espacio es interpretado por Bash como un separador de argumentos de la lnea de comandos.

    $ echo Hola Mundo > ejemplo\ espacio.txt

  • $ cat ejemplo\ espacio.txt

    Entrecomillar los entrecomillados

    Podemos usar el carcter de escape para que no se interpreten los entrecomillados simples o dobles, es decir:

    $ echo \2\*\3\>5\ es una expresion cierta2*3>5 es una expresion cierta

    $ echo \'2\*\3\>5\' es una expresion cierta'2*3>5' es una expresion cierta

    Texto de varias lneas

    Bash nos permite utilizar el carcter de escape para ignorar los retornos de carro de la siguiente forma :

    $ echo Esto es una prueba \> de varias lineas \> linea 1 \> linea 2Esto es una prueba de varias lineas linea 1 linea 2

    Al poner el carcter \ y darle enter en la siguiente linea nos pone >, y nos permite seguir escribiendo.

    Otro ejemplo es usando las comillas simples ' al principio y al final, en vez de usar \.

    $ echo 'Esto es una prueba > de varias lineas> linea 1> linea 2'Esto es una prueba de varias lineas linea 1 linea 2

    Ver historial de comandos

    Para ver el historial de los comandos que ejecutamos habamos visto que existe el comando history, tambin encontramos el comando fc (fix command) es un clsico del C Shell trado al mundo de Bash, que al igual que el comando history lee el archivo .bash_history.

    Como dijimos anteriormente estos comandos internos de bash no contienen man sino la forma de ver ayuda es mediante el comando help.

    $ help fc

    Podemos obtener un listado de los ltimos comandos usados junto con su numero usado :

    $ fc -l

    Es equivalente al comando history excepto que solo el comando fc muestra slo los ltimos comandos del historial y no todo.

    Para editar uno de ellos indicamos su nmero :

    $ fc 20

    Esto nos abrir un editor que depender de la variable EDITOR cual nos habr es decir si queremos usar el editor vi/vim exportamos la variable EDITOR.

  • $ export EDITOR=vim

    El problema de este comando que una vez que salimos del editor ejecuta la sentencia que modificamos.

    Ejecutar comandos anteriores

    Al igual que history podemos ejecutar comando anteriores o por el nmero de comando.

    Comando Descripcin

    !! Ejecutar el ltimo comando.

    !n Ejecutar el comando nmero n.

    !cadena Ejecutar el ltimo comando que empiece por cadena.

    Con la opcin !cadena, ya que con dar las primeras letras de un comando que hayamos ejecutado previamente lo busca en el historial y lo ejecuta, se ejecuta el comando ms reciente que empiece por la cadena.

    Las teclas de control del terminal

    Las teclas de control del terminal son combinaciones de teclas que interpreta el terminal (no Bash).

    $ stty --all

    Veremos que por ejemplo ^C esto significa la tecla Ctrl+C, veremos algunas que son tiles:

    Combinacin de tecla Nombrestty

    Descripcin

    Ctrl+c intr Para el contro

    Ctrl+\ quit Fuerza la parada del comando actual (usar si Ctrl+c no responde).

    Ctrl+d eof Final del flujo de entrada.

    Ctrl+u kill Borra desde la posicin actual al principio de la lnea.

    Ctrl+w werase Borra desde la posicin actual al principio de la palabra.

    Si queremos usar detener un programa por lo general se usa la combinaciones de las teclas Ctrl+C, esto manda un mensaje al programa para que pueda terminar liberando correctamente los recursos asignados. Si por alguna razn no termina es decir ignora el mensaje enviado de Ctrl+C, siempre podemos utilizar Ctrl+\, el cual termina el programa sin esperar a que este libere recursos.

    Modos de edicin en la lnea de comandos

    Por defecto Bash utiliza las teclas del modo de edicin de emacs, pero puede cambiar a las teclas del modo de edicin de vi usando el siguiente comando :

    $ set -o vi

    Y para volver a la combinacin de teclas por defecto o utilizar las teclas de emacs.

    $ set -o emacs

  • Moverse por la lnea

    Para moverse por la lnea de edicin, borrar partes de la lnea, ir al principio y final de la lnea usando la combinaciones de teclas como se muestra en la siguiente tabla.

    Combinacin de teclas Descripcin

    Ctrl+a Ir al principio de la lnea.

    Ctrl+e Ir al final de la lnea.

    Esc+b Ir una palabra hacia atrs (backward).

    Esc+f Ir una palabra hacia adelante (forward).

    Ctrl+b Ir una letra hacia atrs.

    Ctrl+f Ir una letra hacia adelante.

    Ctrl+u Borra de la posicin actual al principio de la lnea.

    Ctrl+k Borra de la posicin actual al final de la lnea.

    Ctrl+w Borra de la posicin actual al principio de la palabra.

    Esc+d Borra de la posicin actual al final de la palabra.

    Ctrl+d Borra el carcter actual hacia adelante.

    Ctrl+y Deshace el ltimo borrado (Yank).

    Buscar y ejecutar comandos del historial

    Ya vimos como movernos, y borrar, ahora si queremos buscar un determinado comando podemos usar la combinacin de teclas Ctrl+R, que nos permite buscar haca atrs en el historial un comando que contenga un determinado texto. Al pulsar esta combinacin de teclas el prompt cambia de forma y segn vamos escribiendo nos va indicando el comando del histrico que cumple el patrn dado.

    La siguiente tabla muestra la combinaciones de teclas :

    Combinacin de teclas Descripcin

    Ctrl+r Realiza una bsqueda hacia atrs (Reverse).

    Intro Ejecuta el comando encontrado.

    Esc Pasa a editar el comando encontrado.

    Ctrl+g Cancela la bsqueda y deja limpia la lnea de edicin.

    Au t ocompletar con el tabulado r

    La tecla de Tab (tabulador) nos ayuda a completar el comando que estamos escribiendo o fichero o directorio.

    Reglas a tener en cuenta :

    1. Si no hay nada que empiece por el texto de la palabra que precede al cursor se produce un pitido que informa del problema.

    2. Si hay un comando (en el PATH), una variable (siempre precedida por $), un nombre de fichero o funcin Bash que comienza por el texto escrito, Bash completa la palabra.

    3. Si hay un directorio que comienza por el nombre escrito, Bash completa el nombre de directorio

  • seguido por una barra de separacin de nombres de directorios /.

    4. Si hay ms de una forma de completar la palabra el shell completa lo ms que puede y emite un pitido informado de que no la pudo terminar de completar.

    5. Cuando Bash no puede completar una cadena (por haber varias posibles que empiecen igual), podemos pulsar dos veces el tabulador y se nos mostrar una lista con las posibilidades cadenas candidatas.

    La librera readline

    Esta librera permite editar lneas de texto usando los modos emacs y vi. Aunque originalmente creada por Bash, actualmente la utiliza miles de comandos de GNU. Esto permite estandarizar las combinaciones de teclas entre muchos comandos.

    Readline se puede personalizar usando ficheros de configuracin o bien asignado combinaciones de teclas para la sesin.

    El fichero de configuracin

    Tiene un archivo global que debe ser colocado en /etc/inputrc, y otro para cada usuario que por defecto se llama .inputrc y que debe ser colocado en el home de cada usuario.

    Cuando bash arranca lee estos ficheros (si existen) y carga sus valores. Dentro del fichero puede haber comentarios (precedidos por #), combinaciones de teclas y asignaciones a variables de readline.

    Combinaciones de teclas

    Lo primero que veremos son las combinaciones de teclas que estn asignadas para una funcin determinada. Para obtener informacin podemos consultar haciendo info readline o en man bash. Estas funciones realizan multitud de operaciones comunes. Para listar estas variables podemos crear el fichero .inputrc en nuestro directorio home y aadir la siguiente entrada :

    # Lista las funciones y variables de readline\C-x\C-f: dump-functions\C-x\C-v: dump-variables

    Una vez que realizamos estos cambios podemos o bien logearnos nuevamente para que tome efecto el archivo .inputrc o bien presionas las teclas Ctrl+x Ctrl+r para que readline vuelva a leer nuevamente el archivo .inputrc.

    Ahora realizamos la combinacin de teclas Ctrl+x Ctrl+f muestre las funciones de readline (que ejecuta la funcin dump-functions() de readline) y Ctrl+x Ctrl+v par que muestre las variables de readline.

    Secuencia Descripcin

    \C- Tecla Ctrl.

    \M- Tecla de escape (Meta).

    \e Secuencia de escape.

    \\ El carcter \ literal.

    \ El carcter literal.

    \' El carcter ' literal.

    Un problema que tiene a veces la terminal es que normalmente la teclas DEL no funciona correctamente, en

  • este caso necesitamos usar una secuencia de escape para hacer que esta tecla llame a la funcin delete-char() de readline.

    # Borra con la tecla DEL\e[3~: delete-char

    readline tiene una serie de variables, que aparecen documentadas junto con las funciones de readline (que podemos consultar con la combinaciones de teclas Ctrl+x Ctrl+v), las cuales podemos asignar un valor en el fichero de configuracin de readline con set.

    Una variable interesante de readline es que al completar con tabulador distingan minsculas de maysculas.

    $ mkdir Videos$ cd vid

    Nos aparecer :

    $ cd Videos/

    Para ello podemos aadir la siguiente lnea al fichero de configuracin de readline :

    # Ignora diferencias de mayusculas/minusculas al# completar con tabuladorset completion-ignore-case on

    Asignacin de teclas de sesin

    Si lo que queremos es probar combinaciones de teclas que no queremos almacenar de forma permanente podemos usar el comando bind, cuya sintaxis es similar a la del fichero de configuracin, pero tenemos que encerrar cada asignacin entre comillas simples o dobles.

    $ bind \\C-x\C-g\: dump-functions

    Si queremos ver las asignaciones de teclas que hay hechas a cada funcin de readline podemos usar el comando :

    $ bind -P

    Otra forma de sacar las funciones de readline :

    $ bind -l

    Podemos sacar todas las asignaciones de teclas en formato inputrc usando el comando :

    $ bind -p

    Con el comando anterior podemos enviar la salida a un fichero para luego editarlo :

    $ bind -p > .inputrc

    Podemos asignar combinaciones de teclas que ejecuten comandos con la opcin -x :

    $ bind -x \\C-l\: ls -la

    Al presionar la tecla Ctrl+l ejecutara ls -la.

  • Los ficheros de configuracin de Bash

    Cada vez que nos logeamos se ejecuta el contenido del fichero /etc/profile, y luego se ejecuta el fichero .bash_profile de nuestro home. Cualquier configuracin que aadamos a .bash_profile no ser efectiva hasta que salgamos de la cuenta y volvamos a logarnos, si queremos ejecutar los cambios que realizamos en este archivo sin salir y volvernos a loguear utilizamos el comando source, el cual ejecuta el contenido del fichero que le digamos.

    $ source .bash_profile

    Tambin podemos usar el punto (.), con lo cual hara lo mismo que source.

    $ . .bash_profile

    Bash permite usar dos nombres alternativos para .bash_profile por razones de compatibilidad histrica: .bash_login, nombre derivado del fichero .login del C Shell, y .profile nombre usado por el Bourne Shell y el Korn Shell. En cualquier caso, slo uno de estos ficheros ser ejecutado: Si .bash_profile existe los dems sern ignorados, sino Bash comprueba si existe .profile. La razn por la que se eligi este orden de bsqueda es que podemos almacenar en .profile opciones propias del Bourne Shell, y aadir opciones exclusivas de Bash en el fichero .bash_profile seguido del comando source .profile para que Bash tambin cargue las opciones del fichero .profile.

    .bash_profile se ejecuta slo al logarnos, si abrimos otro shell (ejecutando bash o su) desde la lnea de comandos de Bash lo que se intenta ejecutar es el contenido de .bashrc. Si .bashrc no existe no se ejecutan configuraciones adicionales al abrir un nuevo shell. Este esquema nos permite separar configuraciones que se hacen una sola vez, al logarnos, de configuraciones que se cambian cada vez que se abre un nuevo shell. Si hay configuraciones en .bashrc que tambin queremos ejecutar al logarnos podemos poner source .bashrc dentro del fichero .bash_profile.

    Por ltimo, el fichero .bash_logout es un fichero que, de existir, contiene ordenes que se ejecutarn al abandonar la cuenta, por ejemplo eliminar ficheros temporales o almacenar datos de actividad de usuarios en un fichero de log.

  • Las variables de entorno

    Nos ayudan a configurar el entorno en el que se ejecutan los programas. Las variables de entorno no pueden tener espacios, y si queremos asignar un valor con espacio debemos de entrecomillarlo, o bien preceder el espacio por un carcter de escape :

    $ NOMBRE='Marcos Pablo'$ echo $NOMBREMarcos Pablo

    $ NOMBRE=Marcos\ Pablo$ echo $NOMBREMarcos Pablo

    Como vemos para obtener el valor de la variable precede del signo $, observamos que las comillas o el carcter de escape no forman parte del valor de la variable una vez que se realiza la asignacin.

  • Para eliminar una variable de entorno usamos el comando unset.

    $ unset NOMBRE

    Es conveniente utilizar los nombre de las variables en maysculas por conviccin.

    Variables y entrecomillado

    Vemos en este caso como combinar la variable con la salida de pantalla utilizando el comando echo.

    $ NOMBRE='Marcos Pablo'$ EDAD=37$ echo Su nombre es : $nombre y la edad es : $edadSu nombre es : Marcos Pablo y la edad es : 37

    Personalizar el prompt

    Podemos personalizar nuestro prompt de Bash usando las variables de entorno PS1, PS2, PS3 y PS4. En la siguiente tabla se muestra las opciones de personalizacin que podemos usar en cualquiera de los prompt.

    Opcin Descripcin

    \a El carcter ASCII bell (007).

    \A La hora en formato HH:MM.

    \d La fecha en formato semana mes da.

    \D {formato} Nos permite personalizar ms la fecha.

    \e El carcter de escape ASCII (033).

    \H Hostname.

    \h El nombre de la mquina hasta el primer punto.

    \j Nmero de jobs hijos del shell.

    \l Nombre del terminal en el que estamos trabajando (p.e. tty2).

    \n Retorno de carro y nueva lnea.

    \r Retorno de carro.

    \s Nombre de shell.

    \t Hora en formato HH:MM:SS con 12 horas.

    \T Hora en formato anterior pero con 24 horas.

    \u Nombre de usuario.

    \v Versin de Bash.

    \w Ruta del directorio actual.

    \W Nombre del directorio actual (sin ruta).

    \# Nmero de comandos ejecutados.

    \! Nmero histrico del comando.

    \$ # si somos root, o $ en caso contrario.

    \nnn Cdigo de carcter a mostrar en octal.

    \\ La barra haca atrs.

    \[ Empieza una secuencia de caracteres no imprimibles, como los caracteres de control de secuencias del terminal.

  • \] Acaba una secuencia de caracteres no imprimibles.

    Un ejemplo sencillo es de poner \w que es el directorio donde estamos parado y esto nos ayuda siempre para saber donde estamos parado.

    $ PS1='\w->'~->

    Donde ~ significa que estamos en el directorio home.

    Es muy tpico querer saber si somos root o cualquier otro usuario de la mquina, para lo cual se usa la opcin \$ que muestra una # si somos root, o un $ en cualquier otro caso.

    $ PS1='\w\$'~$

    Es muy comn que accedamos a servidores remotos por medio de ssh o telnet y no sabes por medio del prompt en que servidor estamos, para eso podemos incorporar en la variables PS1 la opcin \H que nos da el nombre de la mquina donde estamos situados, o la opcin \h que nos da el nombre de la mquina slo hasta el primer punto :

    $ PS1='\h\w\$'centrux~$

    $ PS1='\H\w\$'centrux.org~$

    Cuando nos movemos en distintas tty de la consola como vimos con la teclas Alt+F1 hasta Alt+F6 (desde la tty1 hasta la tty6), es conveniente que en nuestro prompt tengamos tambin que tty es donde estamos.

    $ PS1='[\u@\h@\l] \w\$'[pablo@centrux@1] ~$

    Con la opcin \u es la que indica el nombre del usuario, \l nos indica la tty que estamos.

    Tambin podemos poner color a nuestro prompt, poniendo las secuencias de escape de caracteres no imprimibles tienen que encerrarse ente \[033[ y \]. Para las secuencias de escape de color, tambin deben aparecer, seguidos adems de una m minscula.

    Por ejemplo para incluir texto azul en el prompt :

    $ PS1='\[\033[34m\][\u@\h:\w]$ '

    En este caso el color azul esta dado por el cdigo 34m y en ningn momento se retorna el color habitual, es decir todo lo que escribamos sera de color azul para arreglar esto y que solo nuestro prompt sea de color azul al final tenemos que poner [\033[0m\]

    $ PS1='\[\033[34m\][\u@\h:\w]$ \[\033[0m\]'

    En la siguiente tabla tenemos los colores :

    Color Cdigo Color Cdigo

    Negro 0;30 Gris oscuro 1;30

    Azul 0;34 Azul claro 1;34

    Verde 0;32 Verde claro 1;32

  • Cyan 0;36 Cyan claro 1;36

    Rojo 0;31 Rojo claro 1;31

    Prpura 0;35 Prpura claro 1;35

    Marrn 0;33 Amarillo 1;33

    Gris claro 0;37 Blanco 1;37

    Tambin podemos poner color de fondo, usando 44 para fondo azul, 41 para fondo rojo, etc, como vemos le sumamos 10 + al color.

    Color Cdigo

    Negro 0;40

    Azul 0;44

    Verde 0;42

    Cyan 0;46

    Rojo 0;41

    Prpura 0;45

    Marrn 0;43

    Gris claro 0;47

    Por ejemplo podemos combinar color de fondo azul y color de las letras blancas :

    $ PS1="\[\033[44m\] \[\033[1;37m\][\u@\h:\w]\$ "

    Otros cdigos que disponibles incluyen subrayado, parpadeante, inverso y oculto.

    Tipo Cdigo

    Subrayado 4

    Parpadeante 5

    Inverso 7

    Oculto 8

    $ PS1="\[\033[44m\] \[\033[1;37m\] \[\033[4m\][\u@\h:\w]\$ "

    PS2 es el prompt secundario y por defecto vale >. Se usa cuando escribimos un comando inacabado, por ejemplo :

    $ echo Esto es una prueba de escribir \> en dos lineas.

    Por ltimo, PS3 y PS4 son prompts de programacin y depuracin que veremos mas adelante.

    Variables de entorno internas

    Existen una serie de variables de entorno, las cuales se resumen en la siguiente tabla, estas variables las fija el shell no nosotros.

  • Variable Descripcin

    SHELL Path del fichero que estamos usando.

    LINES Lneas del terminal en caracteres.

    COLUMNS Columnas del terminal en caracteres.

    HOME Directorio home del usuario.

    PWD Directorio actual.

    OLDPWD Anterior directorio actual.

    USER Nombre de usuario en la cuenta donde estamos logados.

    Algunas variables se actualizan dinmicamente, por ejemplo LINES y COLUMNS en todo momento almacenan en nmero de filas y columnas de la terminal, y las usan algunos programas como el editor vi/vim o emacs para modificar su apariencia.

    Exportar variables

    Las variables de entorno que definimos dentro de una sesin de Bash no estn disponibles para los subprocesos que lanza Bash (sol las puede usar Bash y nuestro comandos interactivos y scripts) a no ser que las exportemos con el comando export.

    $ EDITOR=vi$ export EDITOR

    O directamente podemos exportarlo :

    $ export EDITOR=vi

    Podemos obtener un listado de las variables exportadas usando el comando env o el comando export sin argumentos. Para obtener las variables tanto exportadas como no exportadas debemos usar el comando set sin argumentos.

    Programacin bsica del shell

    Un script es un fichero que contiene comandos Bash ejecutables. Una vez que creamos un script con nuestro editor de texto favorito hay dos forma de ejecutarlo.

    Darle permiso de ejecucin tanto para el dueo, grupo y otros (chmod +x archivo_script).Una vez puesto este permiso, podremos ejecutarlo siempre que est en alguno de los directorios indicados en la variable de entorno PATH. Es muy tpico dentro de los script poner como primer linea !#/bin/bash, de esta forma se indica que el script debe ser ejecutado con Bash, aunque bash no sea el shell por defecto, otros scripts para otros lenguajes como awk, ksh o perl tambin se escriben empezando la primera lnea.

    Cuando ejecutamos un script con source, ste se ejecuta dentro del proceso del shell, mientras que si lo ejecutamos como un fichero ejecutable se ejecuta en un subshell.

    Ejemplo :

    $ vi ejemplo.sh

    !#/bin/bashA=10echo $A

  • $ chmod +x ejemplo.sh

    Al llamarlo de la siguiente forma, lo estamos ejecutando en un subshell.

    $ ./ejemplo.sh10

    Veremos que si queremos imprimir el valor de A no mostrara nada :

    $ echo $A

    Ahora lo llamaremos con el comando source o . (punto) y veremos que este se ejecuta en el shell y no el subshell como el ejemplo anterior.

    $ source ejemplo.sh10

    $ echo $A10

    o

    $ . ./ejemplo.sh10

    $ echo $A10

    Funciones

    A diferencia de los scripts, se ejecutan dentro de la memoria del propio proceso de Bash, con lo que son ms eficientes que ejecutar aparte, pero tienen el inconveniente de que tienen que estar siempre cargadas en la memoria del proceso Bash para poder usarse.

    Existe dos formas para definir una funcin :

    El estilo del Bourne Shell : O el estilo del C Shell :

    function nombre_funcion{ comandos bash }

    nombre_funcion(){ comandos bash }

    No existe diferencia entre ellos, para borrar una funcin podemos utilizar el comando unset -f nombre_funcin. Cuando definimos una funcin se almacena como una variable de entorno (con su valor almacenado la implementacin de la funcin). Para ejecutar la funcin escribimos el nombre de la funcin y los parmetros necesarios.

    $ vi funcion.sh

    !#/bin/bashimprimir_valor() {

    A=20echo $A

    }

  • $ chmod +x funcion.sh$ source funcion.sh

    $ imprimir_valor20

    Si queremos borrar una funcin como explicamos anteriormente con el comando unset -f nombre_funcin.

    $ unset -f imprimir_valor$ imprimir_valorbash: imprimir_valor: no se encontr la orden

    Para ver todas las funciones que tenemos declaradas simplemente ejecutamos declare -f, por ejemplo creamos la siguiente funcin.

    $ vi hola.sh

    !#/bin/bashimprimir_saludo() {

    echo Hola : ${USER} }

    $ chmod +x hola.sh$ source hola.sh

    $ imprimir_saludoHola : pablo

    $ declare -fimprimir_saludo () { echo "Hola : ${USER}"}

    Si solo queremos obtener el nombre de la funcin sin el cdigo :

    $ declare -fdeclare -f imprimir_saludo

    Si una funcin tiene el mismo nombre que un script o ejecutable, la funcin tiene preferencia.

    Orden de preferencia de los smbolos de Bash

    A continuacin se enumera el orden de preferencia que sigue Bash a la hora de resolver un smbolo:

    Orden Descripcin

    1 Alias.

    2 Palabras clave (keywords) como function, if o for.

    3 Funciones.

    4 Comandos internos (cd, type,etc).

  • 5 Scripts y programas ejecutables, para los cuales se sigue el orden en que se dan sus directorios en la variable de entorno PATH.

    Si nos interesa conocer la procedencia de un comando podemos usar el comando interno type, si le damos un comando nos indica cual es su fuente.

    Ejemplo :

    $ type lsls es un alias de `ls color=auto'

    $ type -path cat/bin/cat

    Con la opcin -path me devuelve en que ruta se encuentra el comando.

    Podemos tambin pasarle la funcin de un script como la funcin que realizamos anteriormente :

    $ type imprimir_saludoimprimir_valor: es una funcinimprimir_valor () { A=20; echo ${A}}

    Como vimos anteriormente los alias tiene mayor prioridad que las funciones, si declaramos un alias con el mismo nombre de la funcin y luego realizamos un type veremos que nos muestra lo siguiente :

    $ alias imprimir_saludo=ls -a$ type imprimir_saludoimprimir_saludo es un alias de `ls -a'

    Pero si queremos ver todas las definiciones ejecutamos type -a :

    $ type -a imprimir_saludoimprimir_saludo es un alias de `ls -a ' imprimir_saludo: es una funcinimprimir_saludo() {

    echo Hola : ${USER} }

    Si ejecutamos imprimir_saludo como tiene mayor prioridad el alias solo ejecutara el ls y no la funcin.

    $ imprimir_saludo./ ../ .bash_history .vim/ .viminfo

    Si queremos conocer el tipo de un smbolo con la opcin -t, es decir esto nos devolver si es un alias, keyword, function, builtin (comando internos) o file.

    Ejemplo :

    $ type -t lsalias

    $ type -t rmfile

  • $ type -t cdbuiltin

    $ type -t imprimir_saludoalias

    Borramos el alias anteriormente definido con el comando unalias.

    $ unalias imprimir_saludo$ type -t imprimir_saludofunction

    Variables de Shell

    Por convenio las variables de entorno exportadas se escriben en maysculas, acordemonos que GNU/Linux y UNIX deferencia entre minsculas y maysculas.

    Los parmetros posicionales

    Son los en encargados de recibir los argumentos de un script y los parmetros de una funcin. Sus nombres son 1, 2, 3, etc., con lo que para acceder a ellos utilizaremos, como normalmente, el smbolo $ de la siguiente forma $1, $2, $3, etc. Adems tenemos el parmetro posicional 0 que contiene el nombre del script que se esta ejecutando.

    Ejemplo :

    $ vi parametros.sh

    #!/bin/bash# Esto es un ejemplo de script utilizando parametros.

    echo El nombre del script es : $0echo Se pasaron los siguientes parametros : $1 $2 $3 $4

    $ chmod +x parametros.sh$ ./parametros.sh hola mundoEl nombre del script es : parametros.shSe pasaron los siguientes parametros : hola mundo

    Como los parmetros $3 y $4 no se pasaron son nulos dan a una cadena vaca que no se imprime.

    Podemos definir una funcin y llamarla con el comando source y pasar los parmetros necesarios

    $ vi funcion_01.sh

    function recibir{ echo La funcion $0 echo Recibe como parametros $1 $2 $3 $4}

    $ chmod +x funcion_01.sh$ ./recibirLa funcion recibirRecibe como parametros buenos dias Marcos

  • Variables locales y globales

    Los parmetros son locales al script o funcin y no se puede acceder o modificar desde otra funcin. Por ejemplo el siguiente script.

    $ vi funcion_01.sh

    function recibir{ echo La funcion $0 echo Recibe como parametros $1 $2 $3 $4}

    Ejemplo de variable global.

    $ vi funcion_01.sh

    function recibir{ nombre='Dentro de la funcion'}

    nombre='Nombre del programa funcion_01.sh'echo $nombre

    recibirecho $nombre

    $ chmod +x funcion_01.sh$ ./funcion_01.shNombre del programa funcion_01.shDentro de la funcion

    Si queremos que una variable sea local debemos poner el modificador local, el cual slo se puede usar dentro de las funciones (no en los scripts). Veremos en el ejemplo que se crea una variable local nombre y no modifica a la global del script.

    $ vi funcion_01.sh

    function recibir{ local nombre='Dentro de la funcion'}

    nombre='Nombre del programa funcion_01.sh'echo $nombre

    recibirecho $nombre

    $ chmod +x funcion_01.sh$ ./funcion_01.shNombre del programa funcion_01.shNombre del programa funcion_01.sh

    Este ejemplo combina tanto la variable local como global. Como vemos por defecto las variables son

  • globales.

    $ vi funcion_02.sh

    function soy{ local donde='Dentro de la funcion' quiensoy=Marcos}

    donde='En el script'echo $donde

    soyecho $dondeecho Soy $quiensoy

    $ chmod +x funcion_02.sh$ ./funcion_02.shEn el scriptEn el scriptSoy Marcos

    Las variables $*, $@ y $#

    La variable $# contiene la cantidad de parmetros que se pasan, este valor es de tipo cadenas de caracteres, ms adelante veremos como podemos convertir este valor a nmero para poder operar con el.

    Tanto $* como $@ nos devuelven los parmetros pasados al script o funcin.

    Ejemplo :

    $ vi parametros_01.sh

    echo Nombre del script : $0 recibe : $# parametros : $*echo Nombre del script : $0 recibe : $# parametros : $@

    $ chmod +x parametros_01.sh$ ./parametros_01.sh 1 2 3 4 5 Nombre del script : ./parametros_01sh recibe : 6 parametros : 1 2 3 4 5 6Nombre del script : ./parametros_01sh recibe : 6 parametros : 1 2 3 4 5 6

    La diferencia que existe entre $* y $@ :

    Podemos cambiar el smbolo que usa $* para separar los argumentos indicndolo en la variable de entorno IFS (Internal Field Separator), mientras que $@ siempre usa como separador un espacio.

    Ejemplo:

    $ vi parametros_01.sh

    IFS=','echo Nombre del script : $0 recibe : $# parametros : $*echo Nombre del script : $0 recibe : $# parametros : $@

  • $ ./parametros_01.sh 1 2 3 4 5 Nombre del script : ./parametros_01sh recibe : 6 parametros : 1,2,3,4,5,6Nombre del script : ./parametros_01sh recibe : 6 parametros : 1 2 3 4 5 6

    Expansin de variables usando llaves

    Realmente la forma que usamos para expandir una variable $variable es una simplificacin de la forma ms general ${variable}. La simplificacin se puede usar siempre que no existan ambigedades. La forma ${variable} se usa siempre que la variable vaya seguida por una letra, dgito o guin bajo (_), en caso contrario podemos usar la forma simplificada $variable.

    Ejemplo :

    $ nombre=Marcos$ apellido=Russo$ echo $nombre_$apelldioRusso

    Se produce esto porque $nombre_ piensa que es una variable hasta el otro smbolo $.

    $ nombre=Marcos$ apellido=Russo$ echo ${nombre}_${apelldio}Marcos_Russo

    Tambin lo tenemos que usar las llaves cuando vamos a sacar el dcimo parmetro posicional. Es decir si usamos $10, bash lo expandir por $1 seguido de un 0, entonces la forma de usarlo para que lo interprete como el dcimo parmetro es usando ${10}.

    Operadores de cadena

    Nos permiten manipular cadenas sin necesidad de escribir complicadas rutinas de procesamiento de texto. Los operadores de cadenas nos permiten realizar las siguientes operaciones :

    Asegurarnos de una variable existe (que est definida y que no es nula).

    Asignar valores por defecto a las variables.

    Tratar errores debidos a que una variable no tiene un valor asignado.

    Tomar o eliminar partes de la cadena que cumplen un patrn.

    Operadores de sustitucin

    Operador Descripcin

    ${variable:-valor} Si variable existe y no es nula retorna el valor de variable, sino retorna valor.

    ${variable:+valor} Si variable existe y no es nula retorna valor, sino retorna una cadena nula.

    ${variable:=valor} Si variable existe y no es nula retorna el valor de variable, sino asigna valor a variable y retorno su valor.

    ${variable:?mensaje} Si variable existe y no es nula retorna el valor de variable, sino imprime variable:mensaje y aborta el script que se est ejecutando (slo en shells no interactivos). Si omitimos mensaje imprime el mensaje por defecto parameter null or not set.

  • ${variable:offset:longitud} Retorna una subcadena de variable que empieza en offset y tiene longitud caracteres. El primer carcter de variable empieza en la posicin 0. Si se omite longitud la subcadena empieza en offset y continua hasta el final de variable.

    Los dos puntos (:) en este operador son opcionales. Si se omiten en vez de comprobar si existe y no es nulo, slo comprueba que exista (aunque sea nulo).

    Ejemplo :

    ${variable:-valor} se utiliza para retornar un valor por defecto cuando el valor de la variable variable est indefinido. Esto no modifica el contenido de variable.

    $ echo ${variable:-10}10

    ${variable:+valor} por contra se utiliza para comprobar que una variable tenga asignado un valor no nulo.

    $ echo ${variable:+1}

    Si variable contiene datos entonces mostrara el valor 1 esto se puede tomar como un valor verdadero. Esto no modifica el contenido de variable.

    ${variable:=valor} que asigna un valor a la variable si sta est indefinida. En el siguiente ejemplo asigna el valor 1 a variable sino tiene valor.

    $ echo ${variable:=1}1

    ${variable:offset:longitud} podemos tomar una parte de la cadena.

    $ variable=Marcos Pablo$ echo ${variable:0:6}Marcos

    $ echo ${variable:7:5}Pablo

    Operadores de bsqueda de patrones

    Un uso frecuente de los operadores de bsqueda de patrones es eliminar partes de la ruta de un fichero, como pueda ser el directorio o el nombre del fichero.

    Un uso frecuente de los operadores de bsqueda de patrones es eliminar partes de la ruta un fichero, como pueda ser el directorio o el nombre del fichero.

    Ejemplo :

    $ ruta=/usr/share/doc/apt/examples/sources.list

    Si ejecutamos la siguiente de operadores de bsqueda de patrones, obtendremos los siguientes resultados:

    Operador Resultado

    ${ruta##/*/} sources.list

    ${ruta#/*/} share/doc/apt/examples/sources.list

  • ${ruta%.*} /usr/share/doc/apt/examples/sources

    ${ruta%%.*} /usr/share/doc/apt/examples/sources

    En la bsqueda de patrones se pueden usar tanto los comodines tradicionales, el siguiente cuadro son los comodines extendidos:

    Operador Descripcin

    ${variable#patron} Si patron coincide con la primera parte del valor de variable, borra la parte ms pequea que coincide y retorna el resto.

    ${variable##patron} Si patron coincide con la primera parte del valor de variable, borra la parte ms grande que coincide y retorna el resto.

    ${variable%patron} Si patron coincide con el final del valor de variable, borra la parte ms pequea que coincide y retorna el resto.

    ${variable/patron/cadena} La parte ms grande de patron que coincide en variable es reemplazada por cadena. La primera forma slo reemplaza la primera ocurrencia, y la segunda forma reemplaza todas las ocurrencias. Si patron empieza por # debe producirse la coincidencia al principio de variable, y si empieza por % debe producirse la coincidencia al final de variable. Si cadena es nula se borran las ocurrencias. En ningn caso variable se modifica, slo se retorna su valor con modificaciones.

    Ejemplo :

    $ ruta=/usr/share/doc/apt/examples/sources.list$ echo ${ruta#/usr/*/doc}/apt/examples/sources.list

    $ echo ${ruta%*.list}/usr/share/doc/apt/examples/sources

    $ echo ${ruta%%/examples/sources.list/}/usr/share/doc/apt

    $ echo ${ruta/usr/var}/var/share/doc/apt/examples/sources

    Un operador muy interesante es ? que es una condicin si no existe tal cosa entonces hacer esto.

    Ejemplo :

    $ vi entrada.sh

    #!/bin/bashfichero_entrada=${1:?'Falta parametros'}

    $ ./entrada.sh./entrada.sh: lnea 1: 1: Falta parametros

    Si queremos ir mostrando linea por linea el PATH tomando como separador los (:), realizamos lo siguiente :

    $ echo -e ${PATH//:/'\n'}/usr/local/bin/usr/bin/bin

  • /usr/local/games/usr/games

    El '\n' significa salto de linea, es decir reemplaza los : por '\n' (salto de linea).

    Operadores longitud

    Tiene la forma ${#variable} donde variable es la variable cuyo valor queremos medir.

    Ejemplo :

    nombre='Marcos Pablo Russo'$ echo ${#nombre}18

    Sustitucin de comandos

    Nos permite usar la salida de un comando como si fuera el valor de una variable. La sintaxis es la siguiente :

    $(comando)

    Las comilla `comando` sirve para realizar la ejecucin de un comando. Aunque en Bash mantiene esta sintaxis por compatibilidad haca atrs, la forma recomendada es mediante el uso de parntesis, que permite anidar sustituciones de comandos.

    Ejemplo :

    $ midir=$(ls $HOME)$ echo $midir

    Tambin podemos cargar el contenido de un archivo a una variable usando $(

  • 0 /usr/include1 /etc2 /usr/share/doc3 ~$ popd/etc /usr/share/doc ~ $ popd/usr/share/doc ~ $ popd~

    Control de flujo

    Las sentencias de control de flujo es un denominador comn de la mayora de los lenguajes de programacin, incluido Bash.

    En este caso veremos las sentencias de control de flujo (if, else, for, while, until, case y select).

    Las sentencias condicionales

    La sentencia condicional tiene el siguiente formato :

    if condicionthen sentenciaselif condicionthen sentenciaselse sentenciasfi

    Este lenguaje nos obliga a que las sentencias estn organizadas con estos retornos de carro, aunque algunas personas prefieren poner los then en la misma lnea que los if, para lo cual debemos de usar el separador de comandos, que en Bash es el punto y coma (;) as :

    if condicion ; then sentenciaselif condicion ; then sentenciaselse sentenciasfi

    Los cdigos de terminacin

    En UNIX los comandos terminan devolviendo un cdigo numrico al que se llama cdigo de terminacin (exit status) que indica si el comando tuvo xito o no.

    Aunque no es obligatorio que sea as, normalmente un cdigo de terminacin 0 significa que el comando termin correctamente, y un cdigo entre 1 y 255 corresponde a posibles cdigos de error.

    La sentencia if comprueba el cdigo de terminacin de un comando en la condicin, si ste es 0 la condicin se evala como cierta.

    Ejemplo :

  • $ vi ir.sh

    #!/bin/bash

    if cd ${1:?"Faltan parametros"}; then echo $1else echo "Directorio $1 no valido"fi

    $ chmod +x ir.sh$ ./ir.sh./ir.sh: lnea 3: 1: Faltan parametros

    $ ./ir.sh xx./ir.sh: lnea 3: cd: xx: No existe el fichero o el directorioDirectorio xx no valido

    $ ./ir.sh /usr/share/doc/usr/share/doc

    Las sentencias return y exit

    Los comandos UNIX retornan un cdigo de terminacin indicando el resultado de una operacin, pero qu si estamos haciendo una funcin. Cmo retornamos el cdigo de terminacin ?.

    Podemos usar la variable especial ?, cuyo valor es $?, y que indica el cdigo de terminacin del ltimo comando ejecutado por el shell.

    Ejemplo :

    $ cd xxbash: cd: xx: No existe el fichero o el directorio

    $ echo $?1

    $ cd /usr/share/doc

    $ echo $?0

    Si estamos en una funcin nosotros necesitamos devolver dicho valor mediante return para poder salir de la funcin, esta sentencia solo puede ser usado dentro de las funciones. Por contra, la sentencia exit puede ser ejecutada en cualquier sitio, y lo que hace es abandonar el script (aunque se ejecute dentro de una funcin), suele usarse para detectar situaciones errneas que hacen que el programa deba detenerse, aunque a veces se utiliza para cerrar un programa.

    Ejemplo :

    $ vi cd.sh

    cd(){ builtin cd "$@" local ct=$? echo "$OLDPWD -> $PWD" return $cd

  • }Como dijimos anteriormente las funciones tiene preferencia sobre los comando internos, como es en este caso la funcin que declaramos anteriormente cd() tiene mayor prioridad que el comando interno cd.

    Para ejecutar el comando interno y no la funcin podemos usar el comando interno builtin, sino quedara en un bucle infinito llamndose a si mismo.

    builtin cd "$@"

    Observamos tambin que tenemos que guardar el resultado devuelto de la anterior linea en una variable y al final retornamos el valor, si no hacemos as y retornamos sin guardarla en una variable, estaramos devolviendo el valor devuelto por el echo $OLDPWD -> $PWD.

    local ct=$?

    Operadores lgicos y cdigos de terminacin

    Podemos combinar varios cdigos de terminacin de comandos mediante los operadores lgicos and (representado con &&) or (representado con ||) y not (representado con !).

    Ejemplo :

    if cd /tmp && cp archivo.tmp $HOME; then fi

    Primero ejecuta el comando cd /tmp si este tiene xito (es decir el cdigo de retorno es 0 verdadero), ejecuta el siguiente comando cp archivo.tmp $HOME, pero si el primer comando falla no verificara el segundo comando, para que se cumpla la condicin ambos comandos deberan de tener xito (si un operando falla ya no tiene sentido evaluar el otro).

    Muchas veces se utiliza el operador && para implementar un if. Para ello se aprovecha el hecho de que si el primer operando no se cumple, no se evala el segundo. Si por ejemplo queremos que se imprima el mensaje No quedan elementos cuando elemento sea 0 podemos realizar el siguiente ejemplo:

    [ $elemento = 0 ] && echo No quedan elemento

    El operador || (or) por contra ejecuta el primer comando, y slo si ste falla se ejecuta el segundo.

    Ejemplo :

    if cp archivo_1.tmp $HOME || cp archivo_2.tmp $HOME; then fi

    En este ejemplo vemos que si se cumple una condicin no comprueba el resto.

    Por ltimo veremos el operador ! (not), que niega un cdigo de terminacin.

    Ejemplo :

    if ! cp archivo_1.tmp $HOME; then Procesa el errorfi

  • Test condicionales

    La sentencia if lo nico que sabe es evaluar cdigos de terminacin. Pero no podemos verificar si un comando se ha ejecutado bien.El comando interno test nos permite comprobar otras condiciones, que le pasamos como argumento, para acabar devolviendo un cdigo de terminacin. Una forma alternativa al comando test es el operador [ ] dentro del cual metemos la condicin a evaluar, es decir, test cadena1 = cadena2 es equivalente a [ cadena1 = cadena2 ]. Los espacios entre corchetes y los operados, o entre los operandos y el operador de comparacin = son obligatorios. Con lo que es coherente con la sintaxis de if que hemos visto en el apartado anterior.

    Usando los test condicionales podemos evaluar atributos de un fichero (si existe, que tipo de fichero es, que permisos tiene, etc), comparar dos ficheros para ver cual de ellos es ms reciente, comparar cadenas, e incluso comparar los nmeros que almacenan las cadenas (comparacin numrica).

    Comparacin de cadenas

    Operador Verdadero si ...

    str1 = str2 Las cadenas son iguales.

    str1 != str2 Las cadenas son distintas.

    str1 < str2 str1 es menor lexicogrficamente a str2.

    str1 > str2 str1 es mayor lexicogrficamente a str2.

    -n str1 str1 es no nula y tiene longitud mayor a cero.

    -z str1 str1 es nula (tiene longitud cero).

    Ejemplo :

    $ vi cadenas.sh

    #!/bin/bash

    if [ -z $1 ]; then echo "Cadena nula." exit 1fi

    if [ -z $2 ]; then echo "Cadena nula." exit 1fi

    if [[ $1 = $2 ]]; then echo "Son iguales las cadenas."elif [[ $1 > $2 ]]; then echo "La primer cadena es mas grande que la segunda cadena."else echo "La segunda cadena es mas grande que la primer cadena."fi

    $ chmod +x cadenas.sh$ ./cadenas.sh

    Cadena nula.

  • $ ./cadenas.sh a aSon iguales las cadenas.

    $ ./cadenas.sh a b La segunda cadena es mas grande que la primer cadena.

    $ ./cadenas.sh b a La primer cadena es mas grande que la segunda cadena.

    Comparacin numrica de enteros

    Tambin permite comparar variables que almacenan cadenas interpretando estas cadenas como nmeros, para ello se deben de utilizar los siguiente operadores que se muestran en la siguiente tabla :

    Operador Descripcin

    -lt Menor que.

    -le Menor o igual que.

    -eq Igual.

    -ge Mayor o igual que.

    -gt Mayor que.

    -ne No son iguales.

    Los test de condicin (las que van entre corchetes [ ]) tambin se pueden combinar usando los operadores lgicos &&, || y !.

    if [ condicion ] && [ condicion ]; then

    Tambin es posible combinar comandos del shell con test de condicin:

    if comando && [ condicion ]; then

    Adems a nivel de test de condicin (dentro de los [ ]) tambin se pueden usar operadores lgicos, pero en este caso debemos de usar los operadores -a (para and) y -o (para or).

    Ejemplo :

    $ vi comparacion_valores.sh

    #!/bin/bash

    valor_producto_1=$1valor_producto_2=$2

    if [ ${valor_producto_1} -le ${valor_producto_2} -a ${valor_producto_1} -le 10 ]then echo "El producto ingresado es menor o igual al producto2 y menor o igual a 10"fi

    $ chmod +x comparacion_valores.sh$ ./comparacion_valores.sh 10 20 El producto ingresado es menor o igual al producto2 y menor o igual a 10

    Aunque el operador lgico -a tiene menor precedencia que el operador de comparacin -le, en expresiones complejas conviene usar parntesis que ayuden a entender la expresin, pero si los usamos dentro de un test

  • de condicin conviene recordar dos reglas :

    Los parntesis dentro de expresiones condicionales deben ir precedidos por el carcter de escape \ (para evitar que se interpreten como una sustitucin de comandos).

    Los parntesis, al igual que los corchetes, deben de estar separados por un espacio.

    El ejemplo anterior se puede tambin escribir de la siguiente manera :

    if [ \( ${valor_producto_1} -le ${valor_producto_2} \) -a \( ${valor_producto_1} -le 10 \) ]then echo "El producto ingresado es menor o igual al producto2 y menor o igual a 10"fi

    Comprobar atributos de ficheros

    El tercer tipo de operadores de comparacin nos permiten comparar atributos de fichero. Existen 22 operadores de este tipo.

    Operador Verdadero si ...

    -a archivo archivo existe.

    -b archivo archivo existe y es un dispositivo de bloque.

    -c archivo archivo existe y es un dispositivo de carcter.

    -d archivo archivo existe y es un directorio.

    -e archivo archivo existe (equivalente a -a).

    -f archivo archivo existe y en un archivo regular.

    -g archivo archivo existe y tiene activo el bit de setgid.

    -G archivo archivo existe y es posedo por el grupo ID efectivo.

    -h archivo archivo existe y es un enlace simblico.

    -k archivo archivo existe y tiene el sticky bit activado.

    -L archivo archivo existe y es un enlace simblico.

    -N archivo archivo existe y fue modificado desde la ltima lectura.

    -O archivo archivo existe y es posedo por el user ID efectivo.

    -p archivo archivo existe y es un pipe o named pipe.

    -r archivo archivo existe y podemos leerlo.

    -s archivo archivo existe y no est vaco.

    -S archivo archivo existe y es un socket.

    -w archivo archivo existe y tenemos permiso de escritura.

    -x archivo archivo existe y tenemos permiso de escritura, o de bsqueda si es un directorio.

    archivo1 -nt archivo2 La fecha de modificacin de archivo1 ms moderna que (Newer Than) la de archivo2.

    archivo1 -ot archivo2 La fecha de modificacin de archivo1 ms antigua que (Older Than) la de archivo2.

    archivo1 -ef archivo2 archivo1 y archivo2 son el mismo archivo (Equal File).

  • Ejemplo :

    $ vi archivo_01.sh

    #!/bin/bash

    if [ -z "$1" ]then echo "Forma de uso :" echo "" echo "$0 nombre_archivo|directorio" echo "" exit 1fi

    if [ -d "$1" ]then echo "Es un directorio"fi

    if [ -L "$1" ]then echo "Es un enlace simblico"fi

    if [ -w "$1" ]then echo "Tiene permiso de escritura"fi

    if [ -x "$1" ]then echo "Tiene permiso de ejecucion"fi

    $ chmod +x archivo_01.sh$ ./archivo_01.sharchivo_01.sh nombre_archivo|directorio

    $ ./archivo_01.sh /usr/share/docEs un directorioTiene permiso de ejecucion

    El bucle for

    El bucle for en Bash es un poco distinto a los bucles de otros lenguajes como Java o C. Aqu no se repite un nmero fijo de veces, sino que se procesan las palabras de na frase una a una.

    La sintaxis es la siguiente :

    for variable [in lista]do Sentencias que usan $variable ...done

  • Si se omite in lista, se recorre el contenido de $@, pero aunque vayamos a recorrer esta variable, es conveniente declararla explcitamente.

    Ejemplo :

    for planeta in Mercury Venus Terra Marte Jupiter Saturnodo echo $planetadone

    La lista del bucle for puede contener comodines. Por ejemplo, el siguiente bucle muestra informacin detallada de todos los archivos que contiene un directorio actual :

    for archivos in *do ls -l $archivosdone

    Para recorrer los argumentos recibidos por el script, lo correcto es utilizar $@ entrecomillado, tanto $* como $@ sin entrecomillar interpretan mal los argumentos con espacios, y $* entrecomillado considera un slo elemento a todos los argumentos.

    Ejemplo :

    $ vi argumentos.sh

    for arg in $*do echo "Elemento: $arg"done

    for arg in $@do echo "Elemento: $arg"done

    $ chmod +x argumentos.sh$ ./argumentos.sh 1 2 3 4Elemento: 1 2 3 4Elemento: 1Elemento: 2Elemento: 3Elemento: 4

    Como vemos con $* los parmetros pasados los mantiene en una misma linea, mientras que con $@ lo tenemos cada parmetros en distintas lineas.

    La sentencia select

    Nos permite generar fcilmente un men simple. Su sintaxis es la siguiente :

    select variable [in lista]do Sentencias que usan $variabledone

    Observamos que tiene la misma sintaxis que el bucle for, excepto por la keyword select en vez de for. De

  • hecho si omitimos in lista tambin se usa por defecto $@. Lo que genera la sentencia es un men con los elementos de lista, donde asigna un nmero. El valor elegido se almacena en variable, y el nmero elegido en la variable REPLY. Una vez elegida una opcin por parte del usuario, se ejecuta el cuerpo de la sentencia y el proceso se repite en un bucle infinito.

    El bucle se puede abandonar usando la sentencia break, se usa para abandonar un bucle, se puede usar tanto en el caso de select, como tambin en los bucles for, while y until.

    $ vi select.sh

    options1="option1 option2 quit"echo opciones : $options1select opt in $options1 ; do echo $opt if [ "$opt"="quit" ]; then exit fidone

    $ chmod +x select.sh$ ./select.sh

    opciones : option1 option2 quit1) option12) option23) quit#?

    Como vemos el prompt que nos muestra es #? este lo podemos cambiar ya que es la variable PS3 este mismo lo podramos modificar de la siguiente manera :

    $ vi select.sh

    PS3='Elija las siguientes opciones : 'options1="option1 option2 quit"echo opciones : $options1select opt in $options1 ; do echo $opt if [ "$opt"="quit" ]; then exit fidone

    $ ./select.sh

    opciones : option1 option2 quit1) option12) option23) quitElija las siguientes opciones :

  • Opciones de la lnea de comandos, expresiones aritmticas y arrays

    A lo largo de este tema aprenderemos a realizar dos operaciones frecuentes en la programacin de scripts: La primera es recibir opciones (precedidas por un guin) en la lnea de comandos. La segunda es aprender a realizar operaciones aritmticas con las variables, de esta forma superaremos la limitacin de que estbamos teniendo, de que todas nuestras variables slo contenan cadenas de caracteres.

    Opciones de la lnea de comandos

    Es muy tpico que los comandos UNIX tengan el formato :

    comando [-opciones] argumentos

    Las opciones suelen preceder a los argumentos y tienen un guin delante y una abreviatura del significado de la opcion, mientras que se ponen dos guiones cuando indicamos la opcin completa es decir :

    $ ls -R

    o

    $ ls --recursive

    Supongamos el siguiente ejemplo donde le pasamos argumentos :

    ./hacer -o hola mundo.txt

    $0 $1 $2 $3

    El problema est en que normalmente las opciones son opcionales, es decir, pueden darse o no, con lo que el script que procesa la opcin anterior debera tener la forma :

    if [ $1 = -o ]; then Ejecuta la operacin con $2 y $3else Ejecuta la operacin con $1 y $2fi

    En consecuencia, cuando el nmero de opciones crece, la programacin de script se vuelve engorrosa.

    La sentencia shift

    Esta sentencia nos permite solucionar este problema.

    shift [n]

    Donde n es el nmero de desplazamiento a la izquierda que queremos hacer con los argumentos. Si se omite n por defecto vale 1. En el ejemplo anterior si ejecutamos el comando shift 1, $1 pasar a ser hola.txt y $2 pasa a ser mundo.txt, y la opcin se pierde.

    if [ $1 = -o ]; then Procesa -o shiftfiEjecuta la operacin con $1 y $2

    El siguiente ejemplo muestra mejor el uso de shift, donde veremos que recibe tres parmetros posibles .

  • while [ -n "$(echo $1 | grep '^-')" ]do case $1 in -a) echo "Valor : -a" ;; -b) echo "Valor : -b" ;; -c) echo "Valor : -c" ;; *) echo "forma de uso : $0 [-a] [-b] [-c] args..." exit 1 ;; esac shiftdone

    echo "Argumentos : "

    La condicin del bucle busca la expresin regular '^-' significa cualquier cosa que empiece (^) por un guin (-), cada vez que procesamos una opcin ejecutamos shift para desplazar una vez los argumentos.

    Tambin puede ser que cada parmetro tenga su propio argumento, por ejemplo que la opcin -b recibe a continuacin un argumento. En ese caso deberamos modificar el bucle anterior para leer este argumento :

    while [ -n "$(echo $1 | grep '^-')" ]do case $1 in -a) echo "Valor : -a" ;; -b) echo "Valor : -b $2" shift ;; -c) echo "Valor : -c" ;; *) echo "forma de uso : $0 [-a] [-b argumento] [-c] args..." exit 1 ;; esac shiftdone

    echo "Argumentos : "

    En este caso $2 es el argumento de la opcin -b y realizamos un shift para que pase a la prxima opcin, esto lo hace siempre y cuando pasemos como opcin -b.

    El comando interno getopts

    getopts nos permite procesar opciones de lnea de comandos ms cmodamente, el problema de esto es que solo permite una sola letra, es decir -a y no --activo. Adems getopts nos permite procesar opciones cuando estn agrupadas (p.e. -abc en vez de -a -b -c) y sus argumentos de opciones cuando estos no estn separados de la opcin por un espacio (-barg en vez de -b argumento/s) no es conveniente utilizarlo de esta forma siempre conviene tener un espacio es decir -b argumento/s. Generalmente se usa con un bucle while. El comando getopts recibe dos argumentos:

    Es una cadena con las letras de las opciones que vamos a reconocer. Si la opcin tiene un

  • argumento se precede por dos puntos (:). El argumento de la opcin lo podemos leer consultando la variable de entorno OPTARG. El comando getopts coge una de las opciones de la lnea de comandos y la almacena en una variable cuyo nombre se da como segundo argumento. Mientras que el comando encuentra opciones devuelve el cdigo de terminacin 0, cuando no encuentra ms opciones devuelve el cdigo de terminacin 1.

    OPTARG = son los argumentos que se pasan.OPTIND = es el numero del primer argumento a procesar.

    while getopts :ab:c optdo case $opt in -a) echo "Valor : -a" ;; -b) echo "Valor : -b $OPTARG" ;; -c) echo "Valor : -c" ;; *) echo "forma de uso : $0 [-a] [-b argumento] [-c] args..." exit 1 ;; esacdoneshift $(($OPTIND -1))echo "Argumentos : "

    Observamos que no hace falta que ponemos shift dentro del bucle ya que getopts es lo suficientemente inteligente como para devolvernos cada vez una opcin distinta. Lo que s hemos hecho al final del bucle es desplazar tantas veces como argumentos con opciones hayamos encontrado. Para eso getopts almacena en la variable de entorno OPTIND el nmero del primer argumento a procesar.

    VERRRRRRRRRRRRRRRR

    Variables con tipo

    Hasta ahora las variables slo podan contener cadenas de caracteres, despus se introdujo la posibilidad de asignar atributos a las variables que indican, por ejemplo que son enteras o de slo lectura. Para fijar los atributos de las variables tenemos el comando interno declare, el cual tiene la siguiente sintaxis:

    declare [-afFirx] [-p] name[=value]

    La siguiente tabla muestra las opciones dada por este comando, para activar un atributo se precede la opcin por un guin -, con lo que para desactivar un atributo decidieron preceder la opcin por un +.

    Opcin Descripcin

    -a La variable es de tipo array.

    -f Mostrar el nombre e implementacin de las funciones.

    -F Mostrar slo el nombre de las funciones.

    -i La variable es de tipo entero.

    -r La variable es de slo lectura.

    -x Exporta la variable (equivalente a export).

    Si solo escribimos el comando declare sin ningn argumento veremos que nos muestra todas las variables de

  • entorno.

    $ declareBASH=/bin/bashBASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepathBASH_ALIASES=()BASH_ARGC=()BASH_ARGV=()BASH_CMDS=()BASH_COMPLETION=/etc/bash_completionBASH_COMPLETION_COMPAT_DIR=/etc/bash_completion.dBASH_COMPLETION_DIR=/etc/bash_completion.dBASH_LINENO=()

    Si usamos la opcin -f nos muestra slo los nombres de funciones y su implementacin

    $ declare -f_ImageMagick () { local cur prev; _get_comp_words_by_ref cur prev; case $prev in -channel)...

    Y si usamos la opcin -F nos muestra slo los nombres de las funciones existentes.

    $ declare -Fdeclare -f _ImageMagickdeclare -f __expand_tilde_by_refdeclare -f __get_cword_at_cursor_by_refdeclare -f __git_aliased_commanddeclare -f __git_aliasesdeclare -f __git_complete_file

    Las variables que se declaran con declare dentro de una funcin son variables locales a la funcin, de la misma forma que si hubisemos usado el modificador local.

    Por ejemplo el siguiente script muestra como declaramos anteriormente las variables que en definitiva eran de tipo cadenas de caracteres :

    $ var1=5$ var2=4$ resultado=$var1*$var2$ echo $resultado5*4

    Ahora realizamos lo mismo pero utilizando el comando declare -i para indicar que las variables que declaramos son de tipo entero :

    $ declare -i var1=5$ declare -i var2=4$ declare -i resultado

  • $ resultado=$var1*$var2$ echo $resultado20

    Para saber que tipo es la variable que esta declarada con el comando declare utilizamos la opcin -p.

    $ declare -p resultadodeclare -i resultado="20"

    La opcin -x es equivalente a usar el comando export sobre la variable, ambas son formas de exportar una variable de entorno.

    La opcin -r declara a la variable como de slo lectura, con lo que a partir de ese momento no podremos modificar ni ejecutar unset sobre ella.

    $ declare -r resultado$ resultado=$var1*20bash: resultado: variable de slo lectura

    Existe otro comando interno llamado readonly que nos permite declarar variables de slo lectura, pero que tiene ms opciones que declare -r. Con readonly -p nos muestra todas las variables de slo lectura :

    $ readonly -pdeclare -r BASHOPTS="checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath"declare -ir BASHPID=""declare -r BASH_COMPLETION="/etc/bash_completion"declare -r BASH_COMPLETION_COMPAT_DIR="/etc/bash_completion.d"declare -r BASH_COMPLETION_DIR="/etc/bash_completion.d"declare -ar BASH_VERSINFO='([0]="4" [1]="1" [2]="5" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'declare -ir EUID="1000"declare -ir PPID="3118"declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"declare -ir UID="1000"declare -ir resultado="20"

    Adems se nos indica si la variable es de tipo array (-a) o entero (-i).

    Usando la opcin -f podemos hacer una funcin de slo lectura (que el usuario no pueda modificar la funcin). Por ejemplo :

    $ readonly -f mi_funcion

    Muchas veces se ataca un sistema modificando una funcin que se sabe que va a ejecutar un script en modo superusuario (haciendo que la funcin haga algo distinto, o algo ms de lo que haca originalmente). Para evitar este ataque las funciones que van a ejecutarse en modo superusuario se deben de definir slo dentro del script que las usa, aunque a veces se necesitan llamar desde fuera y es recomendable protegerlas con la opcin -r, ya que una vez que una funcin se marca como de slo lectura ya no se puede quitar ese permiso. Es decir si usamos la opcin -n para quitar este atributo, en principio el comando parece funcionar :

    $ readonly -n mi_funcion

    Pero si luego intentamos redefinir la funcin se producir un error indicando que la funcin sigue siendo de slo lectura.

  • Expresiones aritmticas

    Las expresiones aritmticas van encerradas entre $ (( y )), tambin podemos encerrarlas ente $ [ y ], pero est forma est desestimada por Bash con lo que no se recomienda usarla.

    Ejemplo :

    $ echo "$(( 365 - $(date +%j) )) dias para el 31 de Diciembre"

    Nos permite usar los operadores relacionales (, =, ==, !=) y lgicos de C (!, &&, ||) interpretando, al igual que C, el 1 como cierto y el 0 como falso.

    El comando interno let

    Nos permite asignar el resultado de una expresn aritmtica a una variable. Tiene la siguiente sintaxis :

    let var=expresion

    expresion es cualquier expresin aritmtica y no necesita estar encerrada entre $((...)). La diferencia con el comando declare -i, no crea una variable de tipo entero, sino una variable de tipo cadena de caracteres normal.

    Ejemplo :

    $ let a=4*3$ declare -p adeclare a=12$ echo $a12

    Sentencias de control de flujo aritmticas

    Pueden usarse en las distintas sentencias de control de flujo, en cuyo caso la expresin va entre doble parntesis, pero sin el $.

    if ((expresin aritmtica)); then cuerpofi

    O el while aritmtico tendra la forma :

    while ((expresin aritmtica))do cuerpodone

    Ejemplo :

    Este programa genera un nmero aleatorio de 0 a 99, y nos pregunta hasta que acertemos, o fallemos 10 veces. Se utiliza la variable $RANDOM la cual cada vez que se lee devuelve un nmero distinto.

    $ vi obtener.sh

    let intentos=10let solucion=$RANDOM%100while ((intentos-->0))do

  • read -p Indique un numero: numero if ((numero==solucion)); then echo Excelente has ganado... exit elif ((numero0 primero comprueba que intentos sea mayor a 0, y luego le aplica el operador -- que decrementa en uno intentos.

    Arrays

    Bash introdujo los arrays en la versin 2.0. Actualmente Bash slo soporta trabajar con arrays unidimensionales.

    Para declarar un array podemos usar como vimos anteriormente declare -a de la siguiente forma :

    $ declare -a A$ declare -p Adeclare -a A='()'

    No hace falta declarar un array con declare -a tambin podemos crearlo de la siguiente forma :

    $ DIAS=(Lunes Martes Miercoles Jueves Viernes Sabado Domingo)$ declare -p DIASdeclare -a DIAS='([0]="Lunes" [1]="Martes" [2]="Miercoles" [3]="Jueves" [4]="Viernes" [5]="Sabado" [6]="Domingo")'

    Los elementos del array empiezan desde 0 como vemos [0]=Lunes, aunque podemos cambiar los ndices de los elementos indicndolos explcitamente:

    $ DIAS=([1]=Lunes [2]=Martes [3]=Miercoles [5]=Jueves [4]=Viernes [6]=Sabado [7]=Domingo)$ declare -p DIASdeclare -a DIAS='([1]="Lunes" [2]="Martes" [3]="Miercoles" [4]="Viernes" [5]="Jueves" [6]="Sabado" [7]="Domingo")'

    No hace falta suministrar los elementos en orden, ni suministrarlos todos, los ndices donde no colocamos un valor, simplemente valdrn cadena nula.

    $ COLORES=([5]=Rojo Azul Blanco Negro Marron)$ declare -p COLORESdeclare -a COLORES='([5]="Rojo" [6]="Azul" [7]="Blanco" [8]="Negro" [9]="Marron")'

    Otra forma de rellenar un array es la siguiente :

    $ LISTADO=($(ls -1))$ declare -p LISTADOdeclare -a LISTADO='([0]="archivo_01.sh" [1]="archivo_1.tmp" [2]="archivo_2.tmp" [3]

  • ="argumentos.sh" [4]="clientes.txt" [5]="cond2.sh" [6]="cond.sh" [7]="config.conf" [8]="desplaza_parametros.sh" [9]="du-.sh" [10]="eje2.sh" [11]="eje.sh" [12]="entrada.sh" [13]="estado_archivo.sh" [14]="funcion_01.sh" [15]="funcion_02.sh" [16]="funcion.sh" [17]="get_modulos.sh" [18]="imprimir.sh" [19]="ir.sh" [20]="ocupa.sh" [21]="parametros_01.sh" [22]="piladir.sh" [23]="select.sh" [24]="shift.sh" [25]="solucion.sh" [26]="tojpg.sh" [27]="tomar_archivo.sh" [28]="ver_cd.sh" [29]="ver.sh" [30]="x.sh")'

    Para acceder a los elementos usamos el operador corchete [ ] para indicar el ndice del elemento a acceder, y en este caso es obligatorio encerrar entre llaves { } la variable :

    $ echo ${LISTADO[5]}cond2.sh

    Si no indicamos el ndice de elemento, por defecto nos trae el elemento de ndice 0.

    $ echo $LISTADOarchivo_01.sh

    Ahora veremos la forma que no hay que hacer para indicar un elemento determinado, por esa misma razn hay que ponerlo entre llaves :

    $ echo $LISTADO[5]LISTADO[5]

    Otra forma de declarar el array es introducir valores independientemente :

    $ A[2]=Casa$ A[0]=Avion$ A[1]=Tren$ declare -p Adeclare -a A='([0]="Avion" [1]="Tren" [2]="Casa")'

    Podemos usar los ndices especiales * y @, los cuales retornan todos los elementos del array de la misma forma que lo hacen los parmetros posicionales. Cuando no estn encerrados entre comillas dobles ambos devuelven una cadena con los elementos separados por espacio, pero cuando se encierran entre comillas dobles @ devuelve una cadena con los elementos separados por espacio, y * devuelve una cadena con los elementos separados por el valor de IFS.

    $ IFS=,$ echo ${A[*]}Avion Tren Casa

    $ echo ${A[@]}Avion Tren Casa

    $ echo ${A[@]}Avion Tren Casa

    $ echo ${A[*]}Avion,Tren,Casa

    Tambin podemos mostrar su contenido con un bucle for.

    for datos in ${A[*]}do echo $datosdone

  • Los elementos de un array a lo que no se asigna valor tienen una cadena nula, con lo que el bucle anterior slo imprimira los elementos que existan en el array A.

    Podemos consultar la longitud de un array usando la forma ${#array[@]}.

    $ echo ${#A[@]}3

    # nos devuelve slo el nmero de posiciones ocupadas.

    De la siguiente forma si le indicamos un ndice nos dar la longitud del contenido del ndice.

    $ echo ${A[1]}Tren

    $ echo ${#A[1]}4

    Si queremos saber que elementos no son nulos en un array podemos usar la forma ${!array[@]}, esto esta permitido a partir de la versin 3.0 de Bash.

    $ echo ${!A[1]}0 1 2

    Si asignamos un array compuesto a otro array, se pierden los valores existentes, y se asignan los nuevos valores.

    $ echo ${A[@]}Avion Tren Casa

    $ A=(Hola Que tal Adios)$ declare -p Adeclare -a A='([0]="Hola" [1]="Que tal" [2]="Adios")'

    Podemos borrar un elemento del array :

    $ unset A[2]

    $ echo ${A[@]}declare -a A='([0]="Hola" [1]="Que tal" )'

    O bien podemos borrar todo el array :

    $ unset A$ declare -p Abash: declare: A: no se encontr

    Por ltimo vamos a comentar que algunas de las variables de entorno de Bash son arrays. Por ejemplo BASH_VERSINFO es un array de slo lectura con informacin sobre la instancia actual de Bash :

    $ declare -p BAS_VERSINFOdeclare -ar BASH_VERSINFO='([0]="4" [1]="1" [2]="5" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")'

    Otro muy interesante es PIPESTATUS es un array que contiene el cdigo de terminacin del ultimo comando ejecutado :

  • $ ls -l$ declare -p PIPESTATUSdeclare -a PIPESTATUS='([0]="0")'

    $ lsx$ declare -p PIPESTATUSdeclare -a PIPESTATUS='([0]="127")'

    $ ls -l | more $ declare -p PIPESTATUSdeclare -a PIPESTATUS='([0]="0" [1]="0")'

    Redirecciones

    Nosotros anteriormente ya vimos este tema los principales operadores de redireccin que son : >, >, 2> y |, pero esta parte abarca otro grupo de comandos que muchas veces aparecen relacionados con problemas complejos de redireccin.

    En la siguiente tabla explicamos todos estos operadores :

    Operador Descripcin

    cmd1 | cmd2 Pipe; Toma la salida estndar de cmd1 y la enva a la entrada estndar de cmd2.

    >fichero Redirige la salida estndar del programa al fichero.

    >fichero Redirige la salida estndar del programa al fichero. Aade esta a fichero si ste ya existe.

    >|fichero Redirige la salida estndar del programa al fichero. Sobrescribe a ste incluso si la opcin noclobber est activada.

    fichero Usa a fichero tanto para la entrada estndar como para la salida estndar.

    nfichero Usa a fichero tanto para la entrada estndar como para la salida del descriptor de fichero n.

    & Enlaza la salida estndar en el descriptor de fichero n.

    n&m Enlaza el descriptor de salida m en el descriptor de fichero n.

    nfichero Redirige la salida estndar y la salida de error estndar al fichero.

    &- Cierra la salida estndar.

    n>&- Cierra el descriptor de salida n.

  • n nuevo.txt

    En bash existe la opcin noclobber que por defecto no est activa ( y se puede activar con el comando set -o noclobber) que hace que si intentamos sobrescribir un fichero con el operador >(redirigir a un fichero existente) el shell produzca un error y no nos deje ejecutar esta operacin. Podemos forzar que se sobrescriban los ficheros, incluso con esta opcin activada, con el operador >|.

    Los descriptores de fichero

    Hemos visto en captulos anteriores que tenemos tres descriptores principales que el 0 para la entrada estndar (stderr), el 1 para la salida estndar (stdout), y el 2 para la salida de errores estndar (stderr).

    Nos quedan los nmeros del 3 al 9 para abrir descriptores adicionales, el descriptor 5 puede dar problemas ya que cuando el shell ejecuta un subshell el subproceso hereda este descriptor. Esto se hace as porque a veces es til asignar un nmero de descriptor adicional a los descriptores estndar como si fueran una copia adicional de este enlace. Otras veces resulta til asignar un nmero de descriptor adicional a un fichero al que luego nos vamos a referir por su descriptor.

    El operador n>m& enlaza el descriptor n en el descriptor de salida m.

    $ ls -yz >> resultado.logls: invalid option -- 'y'Pruebe `ls --help' para ms informacin.

    $ ls -yz >> resultado.log 2>&1

    El resultado de la linea ilegal la enva por stdout (1), en vez de stderr (2). Si lo hubiramos ejecutado al revs es decir ls 1>&2 lo que habramos hecho es enviar el listado de directorios (stdout) a la salida de errores estndar (stderr).

    El operador n&3

    Asigna el descriptor de fichero de salida 3 al fichero mis.ficheros, y despus enlaza la salida estndar con el descriptor 3, con lo que la salida de ls va al fichero mis.ficheros.

    Tambin podemos usar el operador nfichero para que n sea a la vez un descriptor de entrada y de salida para fichero.

    $ cat clientes.txtJuanPedro

  • Ana

    $ sort 3clientes.txt 0&3$ cat clientes.txtJuanPedroAnaAnaJuanPedro

    Observamos que los clientes ordenados no sobreescriben a los existentes, sino que se escriben a continuacin. Esto se debe a que al leerlos, el puntero a fichero se ha colocado al final, y cuando despus escribimos estamos escribiendo al final de ste.

    El operador nfichero se puede abreviar como fichero, en cuyo caso stdin se convierte en un descriptor de fichero de entrada/salida con fichero como fuente y destino. Es decir, el comando anterior se podra haber escrito como sort cleintes.txt 1>&0. El final del comando 1>&0 se usa para que stdout se enva a stdin (el fichero clientes.txt).

    Hay veces que queremos redirigir ambas salidas : gcc *.c 1>errores.log 2>errores.log una forma mas fcil de abreviar esto es gcc *.c &>errores.log.

    El comando exec

    Este comando nos permite cambiar las entradas y salidas de un conjunto de comandos (de todos los que se ejecutan a partir de l).

    $ vi exec.sh

    exec 6

  • Esto se puede entre otras cosas utilizar en una conexin de un servidor ftp por ejemplo :

    $ vi conexion_ftp.sh

    # Script que sube un fichero a un servidor de FTP# Recibe los siguientes argumentos# $1 Fichero a subir# $2 Servidor FTP# $3 Nombre de usuario# $4 Password# $5 Directorio destino

    ftp

  • -E Desactiva la interpretacin de caracteres precedidos por el carcter de escape. Es la opcin por defecto.

    -n Omite el carcter \n al final de la lnea (es equivalente a la secuencia de escape \c).

    La siguiente tabla muestra las secuencias de escape que acepta echo (cuando se le pasa la opcin -e). Para que estas tengan xito deben de encerrarse entre comillas simples o dobles, ya que sino el carcter de escape \ es interpretado por el shell y no por echo.

    Secuencia de escape Descripcin

    \a Produce un sonido poom (alert).

    \b Borra haca atrs (backspace).

    \c Omite el \n al final (es equivalente a la opcin -n). Debe colocarse al final de la lnea.

    \f Cambio de pgina de impresora (formfeed).

    \n Cambio de lnea.

    \r Retorno de carro.

    \t Tabulador.

    El siguiente ejemplo repite un bucle de 0 a 9, con la opcin \r lo que hace es retorna el cursor en el terminal sin introducir un cambio de lnea (como lo hace el \n).

    $ for ((i=0;i do> echo -n "Procesado $i"> sleep 1> echo -ne "\r"> done

    El comando interno printf

    Con el comando printf podemos formatear la salida por pantalla mientras que con echo no nos deja.

    $ printf Hola MundoHola Mundo

    printf por defecto interpreta las secuencias de escape.

    $ printf Hola Mundo\nHola Mundo

    El formato de este comando es muy parecido al de la funcin printf() del lenguaje C.

    printf cadenaformato [argumentos]

    En la siguiente tabla describimos los formatos que podemos utilizar los cuales empiezan por %.

    Especificador Descripcin

    %c Imprime el primer carcter de una variable cadena.

    %d Imprime un nmero decimal.

    %i Igual que %d (integer).

  • %e Formato exponencial b.precisione[+-]e

    %E Formato exponencial b.precisione[+-]e

    %f Nmero en coma flotante b.precision

    %g El que menos ocupa entre %e y %f

    %G El que menos ocupa entre %E y %f

    %o Octal sin signo

    %s Cadena (string)

    %b Interpreta las secuencias de escape del argumento cadena

    %q Escribe el argumento cadena de forma que pueda ser usado como entrada a otro comando

    %u Nmero sin signo (unsigned)

    %x Hexadecimal con letras en minscula

    %X Hexadecimal con letras en mayscua

    %% % literal

    Ejemplo :

    $ n=30$ nombre=Marcos$ printf El cliente %d es %s\n $n $nombreEl cliente 30 es Marcos

    $ printf |%10s|\n Hola| Hola|

    Si queremos indicar un mximo para la cadena debemos de usar el campo precisin :

    $ printf |%-10.10s|\n Marcos Pablo|Marcos Pab|

    El flag se usa para indicar que queremos alienar a la izquierda :

    $ printf |%-10s|\n Hola|Hola |

    Dos variantes de %s son %b y %q. El especificador de formato %b hace que se interpreten las secuencias de escape de los argumentos. Es decir :

    $ printf %s\n Hola \nAdiosHola \nAdios

    $ printf %b\n Hola \nAdiosHolaAdios

    La siguiente tabla muestra los flags de los especificadores de formato para nmeros.

    Flag Descripcin

    + Preceder por + a los nmeros positivos.

    Espacio Preceder por un espacio a los nmeros positivos.

  • 0 Rellenar con 0's a la izquierda.

    # Preceder por 0 a los nmeros en octal %o y por 0x a los nmeros en hexadecimal %x y %X.

    Ejemplo :

    $ printf |%+10d|\n 56| +56|

    $ printf |%010d|\n 56|0000000056|

    $ printf |%x|\n 56|38|

    $ printf |%#x|\n 56|0x38|

    El comando interno read

    La sintaxis de este comando es :

    read var1 var2

    Esta sentencia lee una lnea de la entrada estndar y la parte en palabras separadas por el smbolo que indique la variable IFS (por defecto espacio o tabulador).

    $ read var1 var2 var3Esto es una prueba

    $ echo $var1Esto

    $ echo $var2es

    $ echo $var3una prueba

    Si omitimos las variables, la lnea entera se asigna a la variable REPLY.

    El uso de read rompe esta forma de programar, con lo que se recomienda usarlo con moderacin. A lo mejor resulta ms conveniente pedir un dato como argumento que pedir al usuario que lo introduzca con read.

    Las principales opciones del comando read :

    Opcin Descripcin

    -a Permite leer las palabras como elementos de un array.

    -d Permite indicar un delimitador de fin de lnea.

    -e Activa las teclas de edicin de readline.

    -n max Permite leer como mximo max caracteres.

    -p Permite indicar un texto de prompt.

    -t timeout Permite indicar un timeout para la operacin de lectura.

  • Ejemplos :

    $ read -a fraseHola mundo nuevo

    $ declare -p frasedeclare -a frase='([0]="Hola" [1]="mundo" [2]="nuevo")'

    La opcin -e es recomendable usarla en general siempre, ya que permite que se puedan usar todas las combinaciones de teclas de readline en el prompt de read.

    La opcin -n nos permite especificar