{"id":2632,"date":"2015-07-26T17:59:53","date_gmt":"2015-07-26T15:59:53","guid":{"rendered":"https:\/\/diocesanos.es\/blogs\/equipotic\/?p=2632"},"modified":"2015-07-15T18:24:55","modified_gmt":"2015-07-15T16:24:55","slug":"bash-teoria-del-interprete-de-ordenes-scripts","status":"publish","type":"post","link":"https:\/\/diocesanos.es\/blogs\/equipotic\/2015\/07\/26\/bash-teoria-del-interprete-de-ordenes-scripts\/","title":{"rendered":"Bash: Teor\u00eda del int\u00e9rprete de \u00f3rdenes (scripts)"},"content":{"rendered":"<p>Si bien lo usamos generalmente para operaciones administrativas o de gesti\u00f3n de archivos, la <b>consola<\/b> de <b>Linux<\/b> extiende su funcionalidad mucho m\u00e1s all\u00e1 de ese prop\u00f3sito, permiti\u00e9ndonos programar <b>scripts<\/b> acorde a nuestras necesidades.<\/p>\n<p style=\"text-align: center;\"><a href=\"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-content\/uploads\/sites\/2\/2015\/07\/bash.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-2633\" src=\"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-content\/uploads\/sites\/2\/2015\/07\/bash-300x226.png\" alt=\"bash\" width=\"300\" height=\"226\" srcset=\"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-content\/uploads\/sites\/2\/2015\/07\/bash-300x226.png 300w, https:\/\/diocesanos.es\/blogs\/equipotic\/wp-content\/uploads\/sites\/2\/2015\/07\/bash.png 600w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Este art\u00edculo no pretende ser una referencia completa sobre la programaci\u00f3n en Bash, sino una introducci\u00f3n a los comandos y estructuras b\u00e1sicas, lo cual nos permitir\u00e1 ampliar el poder de nuestro sistema GNU\/Linux.<\/p>\n<p><!--more--><\/p>\n<h3>\u00bfQu\u00e9 es un \u201cScript\u201d?<\/h3>\n<p>B\u00e1sicamente decimos que es un archivo que contiene c\u00f3digo escrito en determinado lenguaje de programaci\u00f3n que el sistema usa para determinada tarea. No es necesario que tenga una entrada externa ni interfaz gr\u00e1fica, pero s\u00ed que provoque una salida de datos procesados (por m\u00e1s de que el usuario no los vea).<\/p>\n<p>El lenguaje usado por <strong>Bash<\/strong> est\u00e1 definido por su propio int\u00e9rprete y combina la sintaxis de otros Shells, como el Korn Shell (ksh) o el C Shell (csh). Muchos de los comandos que usualmente se usan en la consola tambi\u00e9n pueden usarse en los scripts, salvo aquellos que pertenecen estrictamente a una distribuci\u00f3n en particular.<\/p>\n<h3 id=\"1\">1. Cosas que se le pasan a la mayor\u00eda de la gente<\/h3>\n<p><strong>\/bin\/bash o \/bin\/sh<\/strong><\/p>\n<p>Una de las primeras cosas que hace la m\u00e1quina al ejecutar nuestro script es mirar con qu\u00e9 shell debe hacerlo. En la mayor\u00eda de los sistemas linux actuales <em>\/bin\/sh<\/em> es un link a <em>\/bin\/bash<\/em>, pero no siempre es as\u00ed, por ejemplo en las distribuciones que utilizan <em>busybox<\/em> traen <strong>Sh<\/strong> y normalmente tambi\u00e9n traen <strong>Bash<\/strong>, pero si se utiliza <em>\/bin\/sh<\/em>, no se ejecutar\u00e1 con Bash. Por eso recomiendo utilizar siempre <strong>\/bin\/bash<\/strong>.<\/p>\n<p><strong>Unicode vs ASCII<\/strong><\/p>\n<p>\u00bfOs hab\u00e9is preguntado por qu\u00e9 no pod\u00e9is utilizar \u201c\u00bf\u201d o \u201c\u00f1\u201d en vuestros scripts? \u00bfO utilizar tildes? Puede llegar a ser bastante molesto en scripts interactivos. Eso es porque la codificaci\u00f3n por defecto de Bash es ASCII, o lo que es lo mismo, el set de caracteres del ingl\u00e9s. Para cambiarlo solo tenemos que indicarle a nuestro script que queremos utilizar Unicode. Para eso hay que a\u00f1adir una l\u00ednea justo despu\u00e9s del int\u00e9rprete de comandos:<\/p>\n<pre style=\"font-size: 80%;\"># -*- ENCODING: UTF-8 -*-<\/pre>\n<p>Ojo, es importante que esta l\u00ednea est\u00e9 al principio del script.<\/p>\n<p><strong>Hacer el script ejecutable<\/strong><\/p>\n<p>Es curioso la cantidad de gente que ejecuta los scripts con \u201c<strong>$ bash script.sh<\/strong>\u201d en vez de \u201c<strong>$ .\/script.sh<\/strong>\u201d al fin y al cabo es para eso que hemos definido un int\u00e9rprete de comandos.<\/p>\n<p>Para a\u00f1adirle permisos de ejecuci\u00f3n hay que ejecutar:<\/p>\n<pre style=\"font-size: 80%;\">chmod +x script.sh<\/pre>\n<p><em><span style=\"color: #808080;\">Si nuestro script es ejecutable, lo podemos a\u00f1adir a nuestro PATH y hacer que sea ejecutable desde cualquier lugar\/ carpeta de nuestro equipo. Para eso hay que a\u00f1adir ya sea al .bashrc de nuestro usuario o a \/etc\/bashrc la l\u00ednea<\/span><\/em><\/p>\n<pre style=\"font-size: 80%;\">BIN=\"carpeta donde tengamos los scripts\"\r\nPATH=\"$BIN$PATH\"<\/pre>\n<p><em><span style=\"color: #808080;\">Es una norma de Bash escribir los nombres de variables todo en may\u00fasculas. Mucha gente no sigue esta norma, pero para scripts largos se agradece porque los hacen mucho mas legibles<\/span><\/em><\/p>\n<h3 id=\"2\">2. Estructura de un script<\/h3>\n<ol>\n<li>Cabecera<\/li>\n<li>Definici\u00f3n de variables globales<\/li>\n<li>Ayuda<\/li>\n<li>Funciones<\/li>\n<li>Cuerpo principal<\/li>\n<\/ol>\n<p>La cabecera es donde se indica qu\u00e9 shell queremos utilizar y la codificaci\u00f3n. La ventaja de las funciones es reutilizar c\u00f3digo que se repite escribi\u00e9ndolo una sola vez y hacer mas f\u00e1cil el entendimiento del script, para c\u00f3digo que supera las 100 l\u00edneas es muy \u00fatil.<\/p>\n<p>Para poder utilizar funciones, estas deben estar definidas con antes del cuerpo principal de nuestro script. Y si queremos utilizar variables a nivel global de todo nuestro script, tanto en el cuerpo principal como en las funciones, debemos definirlas al principio de todo, justo despu\u00e9s de la cabecera.<\/p>\n<p>Por \u00faltimo, es de buena pr\u00e1ctica escribir una funci\u00f3n de ayuda para cuando nuestro script se ejecute mal o con malos par\u00e1metros. Obviamente, es esos casos queremos salir del script inmediatamente, sin leer las funciones. Para eso podemos utilizar:<\/p>\n<pre style=\"font-size: 80%;\">function help(){\r\necho \"\"\"Nuestro texto de ayuda bien formateado.\"\"\"\r\nexit\r\nif [[ -z $1 || $1 == \"-h\" || $1 == \"--help\" ]]; then\r\nhelp\r\nfi<\/pre>\n<p>Si a\u00f1adimos \u201cexit\u201d a la funci\u00f3n de ayuda, saldremos del script cada vez que ejecutemos ayuda, por ejemplo despu\u00e9s de mensajes de errores, etc. Nos ahorramos unas cuantas l\u00edneas de c\u00f3digo.<\/p>\n<p>La condici\u00f3n indica mostrar ayuda en pantalla y salir si se ejecuta el script sin par\u00e1metros o si se indica -h\/\u2013help. Si os fij\u00e1is ese es el comportamiento est\u00e1ndar de la mayor\u00eda de programas linux.<\/p>\n<p><span style=\"color: #808080;\"><em>El uso de las 3 comillas con echo permite utilizar saltos de l\u00ednea sin salir del mensaje a mostrar por echo. Para mensajes multil\u00ednea es mucho mas c\u00f3modo utilizar echo una sola vez.<\/em><\/span><\/p>\n<h3 id=\"3\">3. Imprimir en pantalla<\/h3>\n<p>Hay 2 comandos principales para imprimir en pantalla en bash: \u201c<strong>echo<\/strong>\u201d y \u201c<strong>printf<\/strong>\u201c. Los dos son igual de r\u00e1pidos y los dos forman parte de bash. La principal diferencia para un principiante es que echo a\u00f1ade un salto de l\u00ednea al final, mientras que \u201c<strong>printf<\/strong>\u201d no lo hace.<\/p>\n<p>Echo est\u00e1 muy bien y es lo que usa la mayor\u00eda de la gente, sin embargo cuando se leen el INPUT del usuario, o cuando se quieren imprimir variables sacadas de archivos mediante procesado de texto, pueden pasar cosas raras. Normalmente se solucionan f\u00e1cilmente, tan f\u00e1cil como cambiar las dobles comillas a simples o viceversa, o sacar las referencias a variables fuera de las comillas. \u201c<strong>Echo<\/strong>\u201d hace cosas raras tambi\u00e9n dependiendo de c\u00f3mo se ha compilado, si utilizamos siempre Ubuntu o siempre Fedora, no nos afecta, pero si cambiamos de distribuci\u00f3n si.<\/p>\n<p>Por eso utilizo \u201c<strong>printf<\/strong>\u201c, que no me da dolores de cabeza y adem\u00e1s se comporta mas como el \u201c<strong>printf<\/strong>\u201d de C o el \u201c<strong>print<\/strong>\u201d de Python, eso es muy importante si alg\u00fan d\u00eda quer\u00e9is portar vuestro script a otro lenguaje de programaci\u00f3n.<\/p>\n<p><em><span style=\"color: #808080;\">Para una discusi\u00f3n mas extensa pod\u00e9is visitar esta pregunta de <a href=\"https:\/\/unix.stackexchange.com\/questions\/65803\/why-is-printf-better-than-echo#answer-65819\" target=\"_blank\">Unix &amp; Linux en Stack Exchange<\/a>.<\/span><\/em><\/p>\n<h3 id=\"4\">4. Leer el INPUT del usuario<\/h3>\n<p>Todo lo que escribamos despu\u00e9s del nombre de nuestro script y antes de darle a la tecla ENTER queda autom\u00e1ticamente guardado en unas variables especiales. Dichas variables son del tipo $X donde la X es un n\u00famero.<\/p>\n<p>\u201c<strong>$0<\/strong>\u201d indica el nombre de nuestro script y desde \u201c<strong>$1<\/strong>\u201d hasta el infinito son variables todo lo que hemos escrito despu\u00e9s. Por ejemplo:<\/p>\n<pre style=\"font-size: 80%;\">cat &lt;&lt; EOF &gt;&gt; test.sh\r\n#!\/bin\/bash\r\n# -*- ENCODING: UTF-8 -*-\r\nprintf \"\\$0 = $0\\n\"\r\nprintf \"\\$1 = $1\\n\"\r\nprintf \"\\$2 = $2\\n\"\r\nEOF\r\nchmod +x script.sh\r\n.\/script.sh mi archivo.txt<\/pre>\n<p>Creamos un script de prueba, lo hacemos ejecutable y lo ejecutamos con 2 par\u00e1metros. Obtenemos la salida en pantalla de:<\/p>\n<pre style=\"font-size: 80%;\">$0 = .\/script.sh\r\n$1 = mi\r\n$2 = archivo.txt<\/pre>\n<p>Utilizando comillas podr\u00edamos haber pasado \u201cmi archivo.txt\u201d a \u201c$1\u2033.<\/p>\n<p>Tambi\u00e9n podemos leer el INPUT de un usuario con el comando \u201cread\u201d, indicando directamente la variable donde queramos guardar el par\u00e1metro. Por ejemplo:<\/p>\n<pre style=\"font-size: 80%;\">printf \"\u00bfC\u00f3mo te llamas?\\n\"\r\nread NOMBRE\r\nprintf \"Hola, $NOMBRE.\\n\"<\/pre>\n<p><span style=\"color: #808080;\"><em>Ojo con la asignaci\u00f3n de variables. \u201c$VAR = contenido\u201d va a producir un error, no se pueden dejar espacios entre el signo igual, el nombre de la variable y el contenido. El uso correcto es \u201cVAR=contenido\u201d<\/em><\/span><\/p>\n<h3 id=\"5\">5. C\u00e1lculos en Bash<\/h3>\n<p>Para eso podemos utilizar \u201c<strong>expr<\/strong>\u201c, siempre que no necesitemos hacer c\u00e1clculos complejos. Hay que destacar dos cosas, la primera es que \u201c<strong>expr<\/strong>\u201d s\u00f3lo admite n\u00fameros enteros, la segunda es que la divisi\u00f3n devuelve el resultado entero, para ver el resto podemos utilizar \u201c<strong>%<\/strong>\u201c.<\/p>\n<p>Normalmente querremos asignar el resultado de expr a una variable. Eso lo podremos hacer de dos formas:<\/p>\n<pre style=\"font-size: 80%;\">VAR2=`expr $VAR1 \/ 10`\r\nVAR2=$(expr $VAR1 \/ 100)<\/pre>\n<p>Tambi\u00e9n se puede obviar \u201c<strong>expr<\/strong>\u201d utilizando doble par\u00e9ntesis:<\/p>\n<pre style=\"font-size: 80%;\">VAR2=$(($VAR1 \/ 100))<\/pre>\n<p><em><span style=\"color: #808080;\">Para una mayor explicaci\u00f3n de \u201c<strong>expr<\/strong>\u201d o una alternativa que utilice n\u00fameros enteros, pod\u00e9is mirar <a href=\"http:\/\/blog.desdelinux.net\/comando-expr-y-calc-resuelve-expresiones-matematicas-en-la-terminal\/\" target=\"_blank\">esta entrada de KZKG^gaara<\/a>.<\/span><\/em><\/p>\n<h3 id=\"6\">6. Condiciones<\/h3>\n<p>Se ha escrito ya de una manera muy extensa sobre \u201c<strong>if<\/strong>\u201c, \u201c<strong>else<\/strong>\u201c, \u201c<strong>elif<\/strong>\u201d y las condiciones. Pod\u00e9is leer acerca de eso en:<\/p>\n<ul>\n<li><a href=\"http:\/\/blog.desdelinux.net\/programando-en-bash-parte-1\/\" target=\"_blank\">Programando en Bash: parte 1<\/a><\/li>\n<li><a href=\"http:\/\/blog.desdelinux.net\/bash-condiciones-if-then-else\/\" target=\"_blank\">Bash: condiciones if, then, else<\/a><\/li>\n<li><a href=\"http:\/\/blog.desdelinux.net\/comprobar-si-un-archivo-o-carpeta-existe-o-no-y-mas-con-ciclo-if\/\" target=\"_blank\">Comprobar si un archivo o carpeta existe o no y mas con un ciclo if<\/a><\/li>\n<li><a href=\"http:\/\/blog.desdelinux.net\/programando-en-bash-parte-2\/\" target=\"_blank\">Programando en Bash: parte 2<\/a><\/li>\n<\/ul>\n<p>S\u00f3lo quiero destacar la diferencia entre el uso de simples corchetes, \u201c<strong>[ ]<\/strong>\u201c, y dobles corchetes, \u201c<strong>[[ ]]<\/strong>\u201c, para la condiciones. Con dobles corchetes podemos utilizar condiciones adicionales:<\/p>\n<ul>\n<li>\u201c<strong>&amp;&amp;<\/strong>\u201d para y<\/li>\n<li>\u201c<strong>||<\/strong>\u201d para o<\/li>\n<\/ul>\n<p>Para utilizar \u201c<strong>&amp;&amp;<\/strong>\u201d y \u201c<strong>||<\/strong>\u201d con simples corchetes habr\u00eda que separar cada parte entre corchetes separados. El ejemplo utilizado para la parte del script que mira si hay que ejecutar ayuda quedar\u00eda:<\/p>\n<pre style=\"font-size: 80%;\">if [ -z \"$1\" ] || [ \"$1\" == \"-h\" ] || [ \"$1\" == \"--help\" ]]; then\r\nhelp\r\nfi<\/pre>\n<p>Tambi\u00e9n nos evita el tener que escribir los nombres de variables dentro de comillas para prevenir errores. Por ejemplo:<\/p>\n<pre style=\"font-size: 80%;\">if [ $1 = 1 ]; then printf \"El par\u00e1metro es igual a 1.\"; fi\r\nif [ \"$1\" = 1 ]; then printf \"El par\u00e1metro es igual a 1.\"; fi\r\nif [[ $1 = 1 ]]; then printf \"El par\u00e1metro es igual a 1.\"; fi<\/pre>\n<p>Si se ejecuta script.sh sin ning\u00fan par\u00e1metro, el primer caso dar\u00eda un error:<\/p>\n<pre style=\"font-size: 80%;\">bash: [: =: se esperaba un operador unario<\/pre>\n<p><span style=\"color: #808080;\"><em>En Bash \u201c=\u201d y \u201c==\u201d se interpretan ambos de la misma manera. Esto no pasa en otros lenguajes de programaci\u00f3n donde \u201c=\u201d se utiliza s\u00f3lo para asignar variables.<\/em><\/span><\/p>\n<p>De lo que no se ha hablado es de \u201c<strong>case<\/strong>\u201c, que se utiliza para simplificar \u201c<strong>if<\/strong>\u201c. Comencemos por el principio, cuando no tenemos ning\u00fan \u201c<strong>if<\/strong>\u201d se ejecutar\u00e1 todo el c\u00f3digo. Si a\u00f1adimos una condici\u00f3n \u201c<strong>if<\/strong>\u201d tendremos dos casos, uno en el que se ejecuta el bloque de c\u00f3digo que est\u00e1 dentro del \u201c<strong>if<\/strong>\u201d y el otro caso donde no se ejecuta dicho bloque.<\/p>\n<p>Si a\u00f1adimos un \u201c<strong>else<\/strong>\u201c, tambi\u00e9n tendremos dos casos, pero estos dos casos son diferentes a los anteriores. Porque ahora habr\u00e1 dos bloques de c\u00f3digo condicionales, A y B, y un bloque C, que es el resto del programa. Se ejecutar\u00e1 A o B, y C. En el caso anterior era A y C o s\u00f3lo C.<\/p>\n<p>Para evitar escribir condiciones \u201c<strong>if\/else<\/strong>\u201d dentro de \u201c<strong>else<\/strong>\u201d y simplificar la lectura del c\u00f3digo, se creo \u201c<strong>elif<\/strong>\u201c. Cuando tenemos muchas condiciones que dependen de la anterior, por ejemplo rango de n\u00fameros o del tipo:<\/p>\n<pre style=\"font-size: 80%;\">VAR1=$1\r\nif [[ $VAR1 = 1 ]]; then\r\nprintf \"1\\n\"\r\nelif [[ $VAR1 = 2 ]]; then\r\nprintf \"2\\n\"\r\nelif [[ $VAR1 = 3 ]]; then\r\nprintf \"3\\n\"\r\nelse\r\nprintf \"ninguno\\n\"\r\nfi<\/pre>\n<p>En el caso del \u00faltimo \u201c<strong>elif<\/strong>\u201d se leer\u00e1n muchas condiciones. Con case se agiliza este proceso:<\/p>\n<pre style=\"font-size: 80%;\">VAR1=$1\r\ncase $VAR in\r\n1)\r\nprintf \"1\\n\"\r\n;;\r\n2)\r\nprintf \"2\\n\"\r\n;;\r\n3|4)\r\nprintf \"3 o 4, depende\\n\"\r\n;;\r\n*)\r\nprintf \"ninguno\\n\"\r\n;;\r\nesac<\/pre>\n<p>Se leer\u00e1 una variable, en este caso VAR1, y se mirar\u00e1 si equivale a alguno de los casos, si no, se ejecutar\u00e1 el caso por defecto \u201c*\u201d. Los dobles punto y coma equivalen a \u201c<strong>break<\/strong>\u201c, le indican a \u201c<strong>case<\/strong>\u201d que tiene que acabar.<\/p>\n<p><span style=\"color: #808080;\"><em><strong>Case<\/strong>\u201d se puede utilizar tambi\u00e9n como una sucesi\u00f3n de \u201c<strong>if<\/strong>\u201c, para eso hay que utilizar \u201c;;&amp;\u201d (continuar) en vez de \u201c;;\u201d (parar).<\/em><\/span><\/p>\n<h3 id=\"7\">7. Bucles<\/h3>\n<p>Son muy pocos los bucles a saberse en cualquier lenguaje de programaci\u00f3n. En Bash son \u201c<strong>while<\/strong>\u201c, \u201c<strong>until<\/strong>\u201d y \u201c<strong>for<\/strong>\u201c. Se ha escrito ya en el blog acerca de estos:<\/p>\n<ul>\n<li><a href=\"http:\/\/blog.desdelinux.net\/programando-en-bash-parte-1\" target=\"_blank\">Programando en Bash: parte 1<\/a><\/li>\n<li><a href=\"http:\/\/blog.desdelinux.net\/programando-en-bash-parte-2\" target=\"_blank\">Programando en Bash: parte2<\/a><\/li>\n<\/ul>\n<p>Hay dos tipos de bucles \u201c<strong>for<\/strong>\u201c, los que son del tipo \u201c<strong>$ for VAR in LOQUESEA<\/strong>\u201d y lo que son del tipo C \u201c<strong>$ for ((I=0; I&lt;=10; I++))<\/strong>\u201c. El segundo tipo de bucles \u201c<strong>for<\/strong>\u201d son muy \u00fatiles, tiene 3 partes en el inicio del bucle:<\/p>\n<ul>\n<li>Declaraci\u00f3n e iniciaci\u00f3n de variables (En este caso una variable auxiliar \u201cI=0\u2033).<\/li>\n<li>Condici\u00f3n de ejecuci\u00f3n (hasta que I sea menor o igual que 10).<\/li>\n<li>Incremento de la variable auxiliar<\/li>\n<\/ul>\n<p>En mi opini\u00f3n es el bucle m\u00e1s potente de todos. Un ejemplo, que imprime todos los n\u00fameros desde el 0 hasta el 10, ambos inclusive:<\/p>\n<pre style=\"font-size: 80%;\">#!\/bin\/bash\r\nfor ((I=0; I&lt;=10; I++)); do\r\nprintf \"$I\\n\"\r\ndone<\/pre>\n<h3 id=\"8\">8. Funciones<\/h3>\n<p>Hay algunas cosas que Bash no nos permite hacer, \u00bfo si? En un primer vistazo, las funciones de bash impiden hacer 3 cosas: declarar variables locales en las funciones, pasarle par\u00e1metros a las funciones y devolver par\u00e1metros. Todo tiene soluci\u00f3n.<\/p>\n<p>No hacer nada por el estilo de:<\/p>\n<pre style=\"font-size: 80%;\">#!\/bin\/bash\r\nVAR=1\r\nprintc \"$VAR\\n\"\r\nfunction hola() {\r\nVAR=2\r\nprintf \"$VAR\\n\"\r\n}\r\nhola\r\nprintf \"$VAR\\n\"<\/pre>\n<p>Esto imprime en pantalla 1, 2 y 2.<\/p>\n<p>Para declarar variables locales hay a\u00f1adir \u201c<strong>local<\/strong>\u201d cuando se declara:<\/p>\n<pre style=\"font-size: 80%;\">#!\/bin\/bash\r\nVAR=1\r\nprintf \"$VAR1\\n\"\r\nfunction foo() {\r\nlocal VAR1=2\r\nprintf \"$VAR1\\n\"\r\n}\r\nprintf \"$VAR1\\n\"\r\nfoo\r\nprintf \"$VAR1\\n\"<\/pre>\n<p>Esto imprime en pantalla 1, 1, 2, 1.<\/p>\n<p>\u00bfC\u00f3mo se le pasan par\u00e1metros a una funci\u00f3n?<\/p>\n<pre style=\"font-size: 80%;\">#!\/bin\/bash\r\n# -*- ENCODING: UTF-8 -*-\r\nfunction hola() {\r\nprintf \"Hola $1\\n\"\r\n}<\/pre>\n<p>printf \u201c\u00bfC\u00f3mo te llamas?\\n\u201d<br \/>\nread VAR1<br \/>\nhola $VAR1<\/p>\n<p>\u00bfC\u00f3mo se devuelven par\u00e1metros?<\/p>\n<pre style=\"font-size: 80%;\">#!\/bin\/bash\r\n# -*- ENCODING: UTF-8 -*-\r\nfunction hola() {\r\nprintf \"Hola holita\"\r\n}\r\nprintf \"\u00bfC\u00f3mo te llamas?\\n\"\r\nread VAR1\r\nVAR1=$(hola) # AQUI EST\u00c1\r\nprintf \"$VAR1 $VAR2\\n\"<\/pre>\n<p>Como veis esto tiene dos pegas, s\u00f3lo se puede devolver un par\u00e1metro, que puede ser un vector, y si se quiere devolver un par\u00e1metro, ya no se puede imprimir en pantalla desde esa funci\u00f3n.<br \/>\n<span style=\"color: #808080;\"><em>Pod\u00e9is encontrar m\u00e1s cosas de funciones en <a href=\"http:\/\/blog.desdelinux.net\/programando-en-bash-parte-3\/\" target=\"_blank\">este art\u00edculo de Usemoslinux<\/a>.<\/em><\/span><\/p>\n<h3 id=\"9\">9. Getops<\/h3>\n<p>Una de las \u00faltimas cosas de Bash que hay que conocer para crear scripts complejos es \u201c<strong>getops<\/strong>\u201c. Sirve para pasar opciones al script sin importar el orden. La \u00fanica pega es que s\u00f3lo afecta opciones cortas:<\/p>\n<pre style=\"font-size: 80%;\">#!\/bin\/bash\r\n# -*- ENCODING: UTF-8 -*-\r\nVARC=0\r\nfunction help() {\r\nprintf \"Mensaje de ayuda\\n\"\r\nexit\r\n}\r\nif [[ -z $1 ]]; then\r\nhelp\r\nfi\r\nwhile getopts :ha:b:c OPT; do\r\ncase $OPT in\r\nh)\r\nhelp\r\n;;\r\n:)\r\nhelp\r\n;;\r\na)\r\nVARA=$OPTARG\r\n;;\r\nb)\r\nVARB=$OPTARG\r\n;;\r\nc)\r\nVARC=1\r\n;;\r\n\\?)\r\nhelp\r\n;;\r\nesac\r\ndone\r\n# Bloque principal del script que\r\n# hace cosas con VARA, VARB y VARC<\/pre>\n<p>\u201c<strong>Getopts<\/strong>\u201d lee las opciones una a una, por eso se necesita de un bucle.<\/p>\n<p>Hay 2 tipos de opciones que se pueden pasar usando \u201c<strong>getopts<\/strong>\u201c:<\/p>\n<ul>\n<li>Los par\u00e1metros llamados flags, en este caso -c o -h. Se especifican con la letra que queramos usar. Son como variables booleanas, \u201c<strong>true<\/strong>\u201d (est\u00e1n) o \u201c<strong>false<\/strong>\u201d (no est\u00e1n).<\/li>\n<li>Par\u00e1metros con argumentos asociados, -a cualquiercosa, -b cualquiercosa. Se especifican con la letra que queramos con dos puntos a continuaci\u00f3n. El argumento es guardado en OPTARG (este nombre es inalterable).<\/li>\n<\/ul>\n<p><span style=\"color: #808080;\"><em>Los dobles puntos iniciales son para no mostrar errores.<\/em><\/span><\/p>\n<p><strong>\u00bfQu\u00e9 hace este script?<\/strong><\/p>\n<p>Muestra el mensaje de ayuda cuando no se pasa ninguna opci\u00f3n, cuando se pasa el par\u00e1metro \u201c-h\u201d, cuando se pasa un par\u00e1metro no v\u00e1lido (por ejemplo \u201c-x\u201d, esto lo hace \u201c\\?\u201d) o cuando se pasa un par\u00e1metro v\u00e1lido sin argumento (\u201c:\u201d). En el resto de los casos guarda la presencia de \u201c-c\u201d como un 1 en VARC, y los valores pasados con \u201c-a\u201d y \u201c-b\u201d en VARA y VARB.<\/p>\n<p><em>Art\u00edculo original en <strong><a href=\"http:\/\/blog.desdelinux.net\/teoria-de-bash\/\" target=\"_blank\">desdelinux.net<\/a><\/strong><\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Si bien lo usamos generalmente para operaciones administrativas o de gesti\u00f3n de archivos, la consola de Linux extiende su funcionalidad mucho m\u00e1s all\u00e1 de ese prop\u00f3sito, permiti\u00e9ndonos programar scripts acorde a nuestras necesidades. Este art\u00edculo no pretende ser una referencia completa sobre la programaci\u00f3n en Bash, sino una introducci\u00f3n a los comandos y estructuras b\u00e1sicas, &hellip; <a href=\"https:\/\/diocesanos.es\/blogs\/equipotic\/2015\/07\/26\/bash-teoria-del-interprete-de-ordenes-scripts\/\" class=\"more-link\">Seguir leyendo <span class=\"screen-reader-text\">Bash: Teor\u00eda del int\u00e9rprete de \u00f3rdenes (scripts)<\/span> <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[15,5,6],"tags":[66,223],"class_list":["post-2632","post","type-post","status-publish","format-standard","hentry","category-documentacion","category-linux-2","category-practicas","tag-programacion","tag-shell"],"_links":{"self":[{"href":"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-json\/wp\/v2\/posts\/2632","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-json\/wp\/v2\/comments?post=2632"}],"version-history":[{"count":0,"href":"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-json\/wp\/v2\/posts\/2632\/revisions"}],"wp:attachment":[{"href":"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-json\/wp\/v2\/media?parent=2632"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-json\/wp\/v2\/categories?post=2632"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/diocesanos.es\/blogs\/equipotic\/wp-json\/wp\/v2\/tags?post=2632"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}