La bash 1/12 La bash Introducción La bash es una shell de UNIX/Linux. Una shell es una aplicación que facilita la interacción del usuario con el sistema operativo. Los ordenadores de propósito general y servidores se utilizan y administran generalmente a través de la shell. Bash está basada en la shell sh (de hecho su nombre procede de “Bourne-Again SHell”, en referencia a Stephen Bourne que fue el creador de sh). Bash una shell textual (las hay también de tipo gráfico, como la Windows shell). Bash es la shell por defecto de muchos tipos de Linux y, hasta hace unos años, era la shell textual de MacOS. Además de bash y sh, existen otras shell para UNIX/Linux como ksh, dash, tsch, zsh, etc. La bash se ejecuta desde un terminal. Un terminal es un dispositivo, virtual o físico que permite a un operador humano enviar mensajes de texto (generalmente desde un teclado) y recibir información textual de regreso (generalmente por una pantalla; puede incluir también pitidos de “alarma”). Desde Ubuntu, para abrir una terminal virtual desde la shell gráfica (que por defecto es GNOME Shell) se puede pulsar el icono Terminal o la combinación de teclas CTRL+ ALT+T. Se pueden abrir varios terminales a la vez según sean necesarios, identificándose cada terminal como un dispositivo (virtual) distinto. Ej.: $ ps #desde un terminal PID TTY TIME CMD 3261 pts/0 00:00:00 bash 5334 pts/0 00:00:00 ps $ ps #desde otro terminal PID TTY TIME CMD 5355 pts/1 00:00:00 bash 5367 pts/1 00:00:00 ps Como se ve en la columna PID, cada terminal está ejecutando una bash (procesos 3261 y 5355). Por otro lado en la columna TTY (de “TeleTYpewriter”) se identifica cada uno de los terminales (pts/0 y pts/1). El identificador pts viene de Pseudo-Terminal Slave. Como casi todos los dispositivos en Linux, los terminales (incluidos los virtuales) se manejan con ficheros de dispositivos, que cuelgan del directorio /dev. Por ejemplo, pts/0 se corresponde con /dev/pts/0: $ ls -l /dev/pts crw--w---- 1 javier tty crw--w---- 1 javier tty 136, 0 sep 136, 1 sep 4 13:38 0 4 13:34 1 Como puede ver, los ficheros 0 y 1 son de tipo carácter (a diferencia de los asociados a discos, que son de tipo bloque). Pruebe desde el terminal identificado como pts/0 a ejecutar lo siguiente: $ echo hola > /dev/pts/1 Para cerrar un terminal, si está emulado puede cerrarlo como cualquier otra aplicación (en el botón cerrar de la barra de título o pulsando ALT+F4). También puede cerrarlo utilizando métodos que valen para terminales físicos, como el comando interno exit o pulsando, cuando la línea de prompt no contiene ningún otro carácter, CTRL+D (EOT, de End Of Transmission) que se convierte a una condición de EOF (End Of File) que hace que se cierre. La bash 2/12 Características de la bash Muchas características de la bash son comunes a otras shell de Linux. Entre otras características (algunas las hemos visto en el laboratorio pasado; otras las veremos en este y sucesivos laboratorios) están: • Edición de línea, historial comandos, autocompletado, etc. • • Expansión de metacaracteres. Redirección de la E/S. • • Ejecución de comandos externos. Gestión de trabajos (procesos). • • Variables de shell y personalización entorno. Alias. • • Funciones. Aritmética entera. • Arrays. • Proporciona un lenguaje de programación con el que se pueden hacer scripts (programas). Bash se puede utilizar de forma interactiva (con el usuario introduciendo las órdenes por teclado) o no interactiva (en este caso las órdenes suelen darse mediante un fichero/script). Puede ejecutar como vimos los comandos externos de forma síncrona (espera hasta que terminen) o asíncrona (en el caso de que se lancen en segundo plano). Nota: Un alias es un nombre alternativo para un comando. Imagine por ejemplo que le interesa tener acceso a la información de red de su equipo pero está acostumbrado a usar el comando ipconfig de Windows en vez de ip (u otros similares) de Linux. Puede entonces definir un alias (la bash sustituirá el alias por su definición antes de la ejecución). Ej.: $ alias ipconfig='ip a' #cuidado, sin blancos entre = $ ipconfig 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo ... Para ver los alias definidos en su terminal, utilice alias. Para eliminar un alias, utilice unalias. La declaración de este alias es temporal (hasta que cierre la shell). Para que un usuario tenga permanentemente disponible un alias debe incluirlo en su fichero ~/.bashrc que es un fichero para la configuración de la bash del usuario y que se ejecuta cada vez que el usuario inicia un proceso bash. Si se quiere que esté disponible para todos los usuarios, el administrador debe incluir el alias en el fichero /etc/bash.bashrc que también se ejecuta al abrir una bash (y lo hace previamente al fichero .bashrc del usuario). Órdenes internas de la shell Aunque la mayoría de las órdenes son externas, hay también órdenes internas, esto es, proporcionadas por la propia shell (las ejecuta/interpreta sin tener que llamar a otro programa). Es la forma de implementar funcionalidades que no se pueden (o son complicadas de realizar) con programas externos. Ejemplos de órdenes internas son cd, pwd, echo, fg, bg, history, kill, for, while, if, etc. Se puede ver el listado completo de órdenes internas de la bash con la orden help. La bash 3/12 Valor de retorno de una orden Las órdenes, tanto externas como internas, devuelven un valor al finalizar (exit status). El valor es 0 si todo fue correcto y distinto de 0 si hubo un error (hay algún caso en que no es así, como con grep: the exit status is 0 if a line is selected, 1 if no lines were selected, and 2 if an error occurred). Nótese que la mayoría de órdenes devolverán por pantalla un texto con un error cuando éste ocurre para que el usuario sea consciente y pueda actuar al efecto, pero cuando se trata de programar un script manejar errores textuales es más complejo. El valor de retorno de la última orden queda almacenada en la variable de shell ? . Para “acceder” al valor de una variable, como veremos más adelante, se precede de $. Ej.: $ cd dirNoExistente bash: cd: dirNoExistente: No such file or directory $ echo $? #mostramos el valor de retorno de la orden anterior (“cd”) 1 $ echo $? #mostramos el valor de retorno de la orden anterior (“echo”) 0 Si creamos un programa o script, debemos seguir el criterio dado a la hora de devolver el exit status. Entrecomillado La bash tiene una serie de caracteres con un significado especial, por ejemplo * para expansión de nombres de fichero, & para lanzar comandos en segundo plano, | para los pipelines, > para redireccionar la salida, $ para sustitución de variables, # para comentarios, etc. Cuando no queremos que se utilice este significado sino que se trate como un carácter “normal”, hay que “entrecomillarlo”. Hay varias posibilidades: • Carácter de escape \ . Mantiene el literal del carácter que le sigue (no lo interpreta la shell). Se usa también al final de una línea para continuarla. Ej.: $ echo \* \$? \>fichero * $? >fichero • Comillas simples ' ' . Preserva el valor literal de lo contenido entre las comillas. Ej.: $ echo '* $? >fichero' * $? >fichero • Comillas dobles " " . Preserva el valor literal de lo contenido entre las comillas excepto para \ y $ .Ej.: $ echo "* $? >fichero" * 0 >fichero Ciclo de ejecución de una orden De forma resumida, se realizan los siguientes pasos: 1. Leer la orden desde el teclado o un archivo (shell script). La orden puede ocupar más de una línea, por ejemplo si se usa el continuador (el carácter \ a final de línea, como se dijo), una estructuras de control del lenguaje de programación, etc. 2. Divide la entrada en tokens (“palabras” y “operadores”) teniendo en cuenta el entrecomillado. En este paso se realiza también la expansión de los alias. La bash 4/12 3. Analiza los tokens diferenciando comandos simples y compuestos. Comandos compuestos son estructuras de control del lenguaje de programación de la bash (for, if, etc.) y varias formas de agrupamiento que veremos más adelante. 4. Realiza varias expansiones de la shell, separando los tokens expandidos en listas de nombres de fichero y comandos/argumentos. 5. Realiza las redirecciones de la E/S que hubiera (eliminando de la lista de tokens los operadores y operandos relativos a las redirecciones). 6. Ejecución de la orden y, si la orden no ha sido lanzada en segundo plano, esperar a que finalice recogiendo su valor de retorno (exit status) al terminar. 7. Repetir (o terminar shell si la orden era exit). Poner ejemplo, imagíne que tiene esto: $ ls -l -rw-rw-r-- 1 -rw-rw-r-- 1 -rw-rw-r-- 1 $ ls -l *.txt javier javier 50 nov 10 javier javier 200 feb 10 javier javier 200 feb 15 > /tmp/resultado.txt 2020 f1.txt 2021 f2.txt 2021 fichero Aproximadamente, la última línea se procesaría como sigue: 1. Lectura de la línea. 2. División de la línea en tokens: ls, -l, *.txt, >, /tmp/resultado.txt . Como por defecto en Ubuntu ls es alias de ls --color=auto, el token ls se sustituiría por los tokens ls, --color=auto 3. Se identifica y analiza como comando simple. 4. *.txt se expande a f1.txt f2.txt f3.txt . Se identifica el comando (ls) y los argumentos. 5. Se redirecciona la salida estándar a el fichero /tmp/resultado.txt y se elimina de la lista de tokens > y /tmp/resultado.txt 6. Se ejecuta la orden en primer plano. Como ls es una orden externa, la bash realiza una llamada al “sistema operativo” a la función “exec” apropiada con los parámetros adecuados y almacena el valor resultante (exit status) en la variable ? Expansiones de la bash La bash proporciona múltiples expansiones que facilitan su utilización. Las principales son: • Llaves { } • Tilde ~ • Variable (y parámetro) $ • Sustitución de orden $( • Aritmética $(( ) )) • Ficheros/directorios (globbing) Los comportamientos de algunas de las expansiones se pueden configurar con el comando shopt (SHell OPTions). Por ejemplo, vimos en el laboratorio de la semana pasada un ejemplo de comodines en fichero que empezaba así: La bash 5/12 $ ls datos1.txt datos2.txt datosZ.txt fichero.txt $ ls dat*.txt datos1.txt datos2.txt datosZ.txt $ echo *.txt datos1.txt datos2.txt datosZ.txt fichero.txt $ ls prueba* ls: cannot access 'prueba*': No such file or directory $ echo prueba* prueba* Este comportamiento es debido a que, por defecto, la opción nullglob de shopt esta desactivada. Esto significa que si no es posible expandir la cadena a uno o más nombres de fichero, usa la cadena tal cual. Otra posibilidad sería que, si no es posible expandir, se devolviera “vacío”, con lo que el comportamiento sería distinto: $ shopt nullglob #consultamos estado nullglob off $ shopt -s nullglob #habilitamos (set) nullglob $ ls prueba* datos1.txt datos2.txt datosZ.txt fichero.txt $ echo prueba* $ shopt -u nullglob #deshabilitamos (unset) nullglob Si se quiere modificar permanentemente esta u otra opción de la shell, habrá que colocar la instrucción correspondiente en el fichero ~/.bashrc del usuario (o en el fichero /etc/bash.bashrc si se deseara para todos los usuarios). Expansión de llaves Se utiliza para generar cadenas. Opcionalmente las cadenas generadas pueden tener un “prefijo” y/o un “sufijo”. Ej.: $ echo /tmp/{bin,datos,log}.aux #no poner espacios entre las comas /tmp/bin.aux /tmp/datos.aux /tmp/log.aux $ touch /tmp/{bin,datos,log}.tmp $ echo {a,e,i}{A,E,I} #piense qué saldría con {a,e,i} {A,E,I} aA aE aI eA eE eI iA iE iI Permite también generar secuencias de caracteres o números, crecientes o decrecientes, con posibilidad de especificar el incremento (por defecto, 1 o -1 según corresponda). En el caso de secuencias de números, permite tamaños fijos completando con ceros (se especifica añadiendo un 0 a la izquierda al límite inferior o superior). Ej.: $ echo {a..c}{15..12} a15 a14 a13 a12 b15 b14 b13 b12 c15 c14 c13 c12 $ echo {A..D..2}y{1..9..3} Ay1 Ay4 Ay7 Cy1 Cy4 Cy7 $ echo {a..c..2}{00..1000..100} a0000 a0100 a0200 a0300 a0400 a0500 a0600 a0700 a0800 a0900 a1000 c0000 c0100 c0200 c0300 c0400 c0500 c0600 c0700 c0800 c0900 c1000 Es la primera expansión que se realiza. Cualquier carácter especial para otras expansiones se preserva. Es una expansión estrictamente textual. La bash 6/12 Expansión de tilde Se utiliza para obtener ciertos nombres de directorio. Ej. $ echo ~ #directorio home usuario actual /home/jmc $ echo ~pepe #directorio home usuario pepe /home/pepe $ echo ~+ #directorio actual /home/jmc/aso $ echo ~- #directorio anterior /tmp Expansión de variable (y parámetro) Nos vamos a centrar en la expansión de variable, aunque todo lo dicho en esta sección es también válido para los parámetros, pero estos no se verán hasta el próximo laboratorio cuando empecemos con los scripts. En la bash se pueden declarar variables como se muestra en el ejemplo: $ mes=9 #asignamos a la variable mes el valor 9. Cuidado: sin blancos entre = $ mes= #asignamos a la variable mes la cadena vacía (es un valor válido) $ unset mes #eliminamos la variable mes Los identificadores de las variables distinguen mayúsculas y minúsculas (por tanto mes, Mes y MES son tres identificadores distintos). Anteponiendo en la declaración readonly es posible definir “constantes”, que son similares a las variables pero que la shell no permite que se les reasigne un valor. Ej.: $ readonly IVA_NORMAL=21 Precediendo una variable con $ o poniéndola entre llaves precedida por $ (esto permite incluirla dentro de “palabras”) se sustituye por el valor de la variable. Ej.: $ echo Es el mes $mes ... pro${mes}a Es el mes 9 ... pro9a El valor a asignar a las variables es objeto de varias expansiones si las hubiera: tilde, variable y parámetro, sustitución de comando y aritmética (nótese que no se produce expansión de llaves ni de nombres de ficheros). Por ejemplo: $ miDir=~/gastos${mes}.2021 $ echo $miDir /home/jmacias/gastos9.2021 Las variables creadas como se ha indicado aquí se denominan variables de shell, porque no se “exportan” a otros “subshells”. Por ejemplo: $ miVar=hola $ bash #ejecutamos otra shell desde la shell original $ echo $miVar $ exit #volvemos a la shell inicial $ echo $miVar hola Existen las denominadas variables de entorno (environment) que están disponibles una vez definidas para todas las subshell. Para que una variable sea de entorno hay que precederla de export. Ej.: La bash 7/12 $ export miVar=hola $ bash #ejecutamos otra shell desde la shell original $ echo $miVar hola $ exit #volvemos a la shell inicial $ echo $miVar hola Existen una serie de variables de entorno predefinidas. Las variables de entorno se visualizan con env. Podemos encontrar entre otras: HOME: directorio home del usuario PATH: Caminos en los que se buscarán los ejecutables cuando no se especifican. PS1: la cadena de configuración del prompt para la primera línea. PS2: la cadena de configuración del prompt a partir de la primera línea PWD: el directorio actual Ej.: $ echo $HOME entre${HOME}Medias /home/jmc entre/home/jmcMedias La expansión de variable permite “operaciones” más complejas, entre ellas: • Referencia indirecta (acceder a una variable a través de otra): ${!var} $ valor1=Azul $ valor2=Amarillo $ refValor=valor1 #Nótese la diferncia con refValor=$valor1 $ echo ${!refValor} Azul $ refValor=valor2 $ echo ${!refValor} Amarillo • Un valor por defecto si la variable no existe o está vacía: ${var:-valDef} $ unset iva $ echo ${iva:-21} 21 $ iva=4 $ echo ${iva:-21} 4 • Una subcadena desde la posición inicio (se comienza numerando desde 0) de longitud long: ${var:inicio:long} Si se elimina la sección de longitud, devuelve hasta el final de la cadena. Si inicio<0, cuenta desde el final siendo -1 el último carácter y así sucesivamente (debe dejarse un espacio entre : y – para que se diferencie de la expansión vista en el punto anterior). Si long<0, en vez de tratarse como número de caracteres a obtener se interpreta como el carácter, sin llegar a él, hasta el que se va a mostrar empezando desde el final (se numera igual que en el caso de negativos en el inicio). Ej.: La bash 8/12 0 1 2 3 4 5 6 7 8 9 10 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 f u n d a m e n t a l $ palabra=fundamental $ echo ${palabra:0:5} funda $ echo ${palabra:5:5} menta $ echo ${palabra:5} mental $ echo ${palabra: -8: 2} da $ echo ${palabra:3: -4} dame $ echo ${palabra: -6: -4} me $ cosa=a12 $ echo ${palabra:${cosa:1:1}:${cosa:2:1}} un • Longitud de la variable: ${#var} .Ej.: $ echo ${#palabra} 11 Sustitución de orden Consiste en el reemplazo por la salida de una orden. Su sintaxis es: $(orden) .Ej.: (supóngase estamos en el año 2020): $ cal $(date +%Y) 2020 Enero Febrero Marzo do lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá 1 2 3 4 1 1 2 3 4 5 6 7 5 6 7 8 9 10 11 2 3 4 5 6 7 8 8 9 10 11 12 13 14 12 13 14 15 16 17 18 9 10 11 12 13 14 15 15 16 17 18 19 20 21 … $ ficherosAnno=$(ls $(date +%Y)??.txt 2>/dev/null) 202001.txt 202002.txt 202003.txt 202004.txt Sustitución aritmética Evalúa una expresión aritmética entera y sustituye por el resultado. Los operadores, su precedencia, asociatividad y resultados son los mismos que en lenguaje C. Su sintaxis es: $((expresión)) Ej.: $ echo $((45*(9%2)+5)) 50 $ incremento=10 $ cal $(($(date +%Y)+$incremento)) #supóngase estamos en año 2020 2030 Enero Febrero Marzo do lu ma mi ju vi sá do lu ma mi ju vi sá do lu ma mi ju vi sá 1 2 3 4 5 1 2 1 2 6 7 8 9 10 11 12 3 4 5 6 7 8 9 3 4 5 6 7 8 9 ... La bash 9/12 Expansión de nombres de ficheros Esta expansión ya la vimos en el laboratorio de la semana pasada. Se denomina globbing en inglés y consiste en el encaje de ficheros (o directorios) con patrones que contienen comodines (wildcards). Estos son: * cualquier cadena, incluida la vacía ? un carácter cualquiera [ ] cualquier carácter incluido entre los corchetes. Se pueden especificar rangos de caracteres con - y clases de caracteres (ej.: [:alpha:]). [^ ] cualquier carácter no incluido entre los corchetes. Ej.: $ ls 4abc.txt a.3b.txt a222.txt abcd.txt25 $ ls [[:alpha:]][^[:number:]]??.txt* a.3b.txt abcd.txt25 Por defecto, la opción dotglob está desactivada por lo que los ficheros que empiezan por . no encajan con ? ni * sino que el punto se tiene que escribir explícitamente. Se recuerda que las opciones de la bash se cambian con shopt. Estructuración de órdenes en la bash Las formas principales que adoptan las órdenes en la bash son: • Simples • Pipelines • Listas • Compuestas Órdenes simples Secuencia de palabras separadas por “espacios”, terminados por uno de los operadores de control de la shell (nueva línea, |, &, ||, &&, etc.). La primera palabra suele ser la orden a ejecutar y el resto los argumentos. Devuelve un exit status que indica el resultado de la orden (128 + n si fue terminada por la señal n). Ej.: $ grep "ASO $(($(date +%Y)-1))" *.txt Pipelines Secuencia de una o más órdenes simples separadas por pipes, esto es | . La salida estándar de la orden precedente pasa a ser la entrada estándar de la orden siguiente. El exit status es el de la última orden del pipeline. Ej.: $ tail fichero.txt | wc -w Listas de órdenes Secuencia de uno o más pipelines separados por ; , &, && o || y terminadas opcionalmente en ; , & o nueva línea. El exit status es el de la última orden ejecutada. La bash 10/12 orden1 ; orden2 Las órdenes se ejecutan secuencialmente. La shell espera que termine cada comando antes de ejecutar el siguiente. Ej.: $ cd $home; touch fichero; echo Terminado orden1 & orden2 La orden1 se ejecuta asíncronamente en una subshell y pasa a ejecutar de forma síncrona orden2 .Ej.: gedit fichero & date orden1 && orden2 La orden2 se ejecuta solo si el exit status de orden1 ha sido 0. Ej.: $ cd $dir && touch fichero orden1 || orden2 Ej.: La orden2 se ejecuta solo si el exit status de orden1 ha sido distinto de 0. $ cd $dir 2>/dev/null || mkdir $dir Nota: && y || asocian por la izquierda. Comandos compuestos • Bucles (los veremos la semana que viene) • Condicionales (los veremos la semana que viene) • Agrupación de órdenes. Lista de órdenes ejecutada como una unidad. Se pueden ejecutar en una subshell con la sintaxis (lista) o en la misma shell con la sintaxis { lista; } .Ej.: (importante espacios y ; en { lista; } ) $ cd $dir 2>/dev/null || { mkdir $dir ; cd $dir; } $ (echo "Mi $HOME"; ls $HOME) > ver.txt Redirecciones Como vimos la semana pasada, todo proceso tiene abiertos por defecto los siguientes descriptores de fichero (file descriptors): 0 => stdin (entrada estándar; teclado) 1 => stdout (salida estándar; terminal) 2 => stderr (salida error estándar; terminal) Las órdenes suelen usar la entrada y salidas estándar, lo que facilita el encadenamiento de órdenes utilizando pipelines. Además hay varias posibilidades de redireccionar la entrada y salida a fichero, como se verá a continuación. Redirección de la entrada a fichero n<fichero Abre para lectura fichero en el descriptor de fichero n. Si no se especifica n, es 0 (entrada estándar). Ej.: $ cat <fichConTab.txt #cat sin especificar fichero(s), lee de la entrada estándar fichero con tabulaciones $ tr "\t" " " <fichConTab.txt fichero con tabulaciones La bash 11/12 Redirección de la salida a fichero n>fichero Abre para escritura fichero en el descriptor de fichero n. Si no se especifica n, es 1 (salida estándar). Si fichero no existe, se crea. Si existe, se trunca. Ej.: (-d => no liste el contenido de los directorios). $ ls -d [a-d]* >resultado.txt 2>/dev/null Para que en vez de sobreescribir el fichero (si existiera) se añada, se utiliza la sintaxis n>>fichero (si fichero no existe, se crea). Ej.: $ ls -d [w-z]* >>resultado.txt Redirección de la salida a descriptor n>&m (o n>>&m) Abre para escritura (o añadir) el mismo destino que haya en el descriptor m en el descriptor n. Ej.: $ ls a* >resultado.txt 2>&1 $ ls b* >f1 2>f2 3>&1 1>&2 2>&3 Nota: Como es muy común la redirección de la salida de error estándar a la salida estándar, existe también la sintaxis reducida &>fichero . Ej.: $ ls j* &>resultado.txt Aquí documento (here document) <<ETIQUETA La entrada estándar lee del texto indicado hasta que encuentre de nuevo ETIQUETA. Ej.: ftp -n 127.0.0.100 <<FIN user anonymous pepe@uah.es binary lcd $HOME put fichero.dat bye FIN Si se usa <<-ETIQUETA se ignoran tabuladores al inicio líneas, lo que permite en el caso de los script que el código quede más claro. Aquí cadena (here string) <<<cadena La entrada estándar lee de la cadena especificada. Ej.: $ dc <<<"10k 10.0 3.0 / p" Referencias • “Bash reference”. https://www.gnu.org/software/bash/manual/html_node/index.html#SEC_Contents • “Bash Pocket Reference”. Arnold Robbins, 2016. O’Reilly. La bash 12/12 Ejercicios 1- Crea el alias listadir para el comando ls. Pruébalo con alguna opción del ls ¿Funciona? 2- La opción -h (de human) del comando ls hace que los tamaños de fichero, cuando se muestran, aparezcan con un múltiplo adecuado para que sean más fáciles de leer. Se quiere que a veces el ls lleve implícito -h y otras no. Se controlará por una variable llamada HUMANO que tendrá el valor -h o vacía según interese. Declare un alias de ls de forma que incluya esa variable (el alias solo se debe declarar una vez; lo que se modifica cuando se precisa es el contenido de la variable). 3- Escribe la orden para mover, independientemente del directorio en el que te encuentres, el fichero prueba.txt que se podría encontrar en tu home al directorio /tmp. En caso de no existir dicho fichero no debería aparecer ningún error y lo crearía directamente en /tmp conteniendo el calendario del mes actual (cal) y el resultado de un ls del directorio en el que nos encontremos. 4- Escribe la orden para crear en el directorio actual doce ficheros vacíos (touch) cuyos cuatro primeros dígitos sean el año que viene (tiene que funcionar independientemente del año en curso) y los dos siguientes el mes. Por ejemplo, si se ejecuta en 2021 crearía 202201, 202202, …, 202212. 5- Utilice grep para comprobar si en la ruta completa del directorio actual de trabajo aparece la letra s. Si aparece (por ejemplo, estamos en el directorio /tmp/aso), se escribirá exclusivamente un mensaje del estilo “El directorio /tmp/aso contiene la letra s” y si no aparece, no escribirá nada. Haga dos versiones: una redireccionando la salida de echo a grep y otra usando “aquí cadena” como entrada de grep.