EPET N° 1 "UNESCO"

Curso Esencia Linux



Tema 3: El Poder de la Linea de Comandos

Peso: 9

3.1: Almacenamiento de archivos en la linea de comandos

Peso: 2

Prácticamente todas las operaciones que se realizan en el ordenador implican la manipulación de archivos, que a menudo tendrán que ser transportados o almacenados en diferentes lugares. en estos casos, es conveniente generar un archivo que contenga directorios y otros archivos para facilitar su transporte y optimizar la ocupación del espacio en disco.

En Linux, el principal comando para agregar diferentes archivos es tar. Originalmente desarrollado para almacenar copias de seguridad en cinta, hoy en día tar también se utiliza para facilitar el almacenamiento y la distribución de archivos en diferentes medios.

Utilizando tar

Para crear un archivo que contenga todo el directorio /etc y su contenido con tar, podemos usar el comando:

tar cvf etc.tar /etc

A diferencia de otros comandos, la inclusión del guión antes de las opciones de tar es opcional. Las opciones proporcionadas en el ejemplo representan:

El último argumento es el directorio(s) o archivo(s) a incluir. Para extraer el contenido de un archivo tar, la opción utilizada es x:

tar xvf etc.tar

Los archivos serán extraídos con el árbol de directorios completo. Este archivo .tar, aunque contiene varios archivos, no está comprimido.

Compresión

Los principales comandos de compresión en Linux son gzip y bzip2. Para comprimir un archivo con gzip:

gzip etc.tar

Para comprimir con bzip2:

bzip2 etc.tar

El archivo etc.tar.gz o etc.tar.bz2 se creará automáticamente. La principal diferencia entre las dos modalidades de compresión es el algoritmo utilizado. Gzip es más rápido, mientras que bzip2 normalmente ofrece una mejor relación de compresión.

La compresión se puede especificar directamente con el comando tar. Para realizar la compresión con gzip, se utiliza la opción z:

tar czvf etc.tar.gz /etc

Para usar bzip2, se utiliza la opción j:

tar cjvf etc.tar.bz2 /etc

La descompresión puede ser hecha con los comandos gunzip (o gzip -d) y bunzip2 (o bzip2 -d), pero también se puede hacer directamente con el comando tar y con las opciones z y j, respectivamente.

Archivos zip

Otro formato popular para comprimir archivos es el formato zip. Este tipo de archivo también se puede crear desde la línea de comandos, con el comando zip. Al igual que el comando tar, el comando zip acepta caracteres especiales para seleccionar los archivos que serán incluidos:

zip documentos.zip *pdf

En este ejemplo, se creará el archivo documentos.zip que contendrá todos los archivos en el directorio actual terminados con el sufijo pdf. Para extraer el contenido de este archivo, se utiliza el comando unzip documentos.zip, que creará los archivos extraídos en el directorio actual. Para extraer los archivos en otra carpeta, se debe utilizar la opción -d directorio, donde directorio es el directorio que recibirá los archivos extraídos.

3.2: Búsqueda y extracción de información de archivos

Peso: 3

Uno de los comandos más básicos para examinar el contenido de los archivos de texto es less. El comando less simplemente muestra el contenido de un archivo informado como un argumento en la pantalla. Por ejemplo, el contenido del archivo /proc/cpuinfo, que contiene detalles sobre el procesador de la computadora, se mostrará con el comando less /proc/cpuinfo.

Si el tamaño del archivo es mayor que el espacio disponible en la pantalla, se pueden utilizar las teclas de dirección arriba y abajo del teclado para navegar por el archivo. El comando less también permite hacer búsquedas de texto, al presionar la / (barra) en el teclado se puede digitar el texto buscado en la parte de abajo de la pantalla y iniciar la búsqueda presionando Intro. Para localizar a próxima ocurrencia, basta presionar la tecla n. Para encontrar la ocurrencia anterior, basta presionar la tecla ?. Presionar la tecla q finaliza less y retorna al indicador de la linea de comandos.

Redireccionamento

Los procesos Unix (y Linux) de manera predeterminada abren tres canales de comunicación, que les permiten recibir y emitir datos. Esos datos, que pueden ser un texto legible o datos binarios como audio y vídeo, pueden ser redireccionados de y para otros archivos o procesos. en el caso de programas interactivos, el canal de entrada (llamado standard input o stdin) suele ser el propio teclado. Los canales de salida estándar (standard output o stdout) y de salida de error (standard error o stderr) suelen ser la pantalla de la computadora. Los valores numéricos para esos canales son 0 para stdin, 1 para stdout y 2 para stderr. Esos descriptores son definidos automáticamente por los dispositivos virtuales localizados en el directorio /dev: /dev/stdin, /dev/stdout y /dev/stderr.

El flujo de los datos para redireccionamientos y canalizaciones en una linea de comando se de la de izquierda a derecha. Para redireccionar la salida estándar de un comando a un archivo, se utiliza el carácter > después de este, que debe indicar el archivo que recibirá los dados en cuestión. Por ejemplo, se puede redireccionar el contenido del archivo /proc/cpuinfo con el comando:

cat /proc/cpuinfo > ~/cpu.txt

La finalidad del comando cat es semejante a la de less, pero cat envía un contenido para la salida estándar de modo no interactivo. en el ejemplo, la salida de cat es el contenido del archivo /proc/cpuinfo, que fue redireccionado al archivo cpu.txt en el directorio personal del usuario. Si el archivo ~/cpu.txt ya existe, será sobreescrito. Para adicionar los valores sin eliminar el contenido existente, se usa >> en lugar de >.

El contenido redireccionado de manera estándar es el de stdout. Para especificar stderr, se usa 2>. Para redireccionar ambos simultáneamente, se usa &>.

Canalización

Parte de la filosofía Unix es que cada programa tenga una finalidad específica y evite intentar desempeñar todas las tareas solo. en ese contexto, es posible encadenar la ejecución de comandos individuales, cada uno desempeña su función, para obtener un resultado combinado. Ese encadenamiento consiste en enviar la salida de un comando para la entrada de otro comando utilizando el carácter de canalización |, llamado pipe.

Por ejemplo, el contenido de archivo /proc/cpuinfo puede ser direccionado para el comando wc con el comando:

$ cat /proc/cpuinfo | wc
   208    1184    6096

El contenido del archivo /proc/cpuinfo fue redireccionado a la entrada estándar del comando wc, que cuenta número de lineas, palabras y caracteres de un archivo o de contenido recibido por la entrada estándar. El mismo resultado del ejemplo se obtiene al sustituir el uso de cat por el operador de redireccionamiento <:

$ wc < /proc/cpuinfo
   208    1184    6096

El redireccionamiento con < es específico para enviar el contenido de un archivo a la entrada estándar de un programa. en este caso, el flujo de los datos sigue de derecha a izquierda. Por regla general, los comandos que tratan con contenido de texto no requieren el uso de este operador, simplemente informando la ubicación del archivo.

Varias canalizaciones pueden ser hechas en secuencia. A continuación, ambas canalizaciones usadas en una misma linea de comando:

$ cat /proc/cpuinfo | grep 'model name' | uniq
model name      : Intel(R) Xeon(R) CPU           X5355  @ 2.66GHz

El contenido del archivo /proc/cpuinfo fue canalizado con el comando cat /proc/cpuinfo al comando grep 'model name', que seleccionará solo las lineas que contengan el término model name. Por tratarse de un computador con varios procesadores, existen varias lineas model name iguales. La última canalización es del comando grep 'model name' al comando uniq, lo que reduce las líneas repetidas sucesivas a una sola ocurrencia.

Expresiones regulares

Las expresiones regulares son elementos de texto y operadores que forman un patrón, usado para encontrar y opcionalmente modificar una cadena de texto correspondiente. Las expresiones regulares son soportadas por una gran variedad de programas que tratan con texto y que comparten los principales operadores, se listan a continuación:

Uno de los principales programas que utiliza expresiones regulares para realizar búsquedas en texto es grep, cuya aplicación más común es filtrar y facilitar la inspección de archivos muy largos. Puede ser utilizado, por ejemplo, para analizar el contenido del archivo /etc/services, que contiene las definiciones de puertos asociadas a servicios de red:

$ cat /etc/services | grep '^..tp *.../tcp'
lmtp            24/tcp                          # LMTP Mail Delivery
smtp            25/tcp          mail
tftp            69/tcp
http            80/tcp          www www-http    # WorldWideWeb HTTP
sftp            115/tcp
nntp            119/tcp         readnews untp   # USENET News Transfer Protocol
qmtp            209/tcp                         # Quick Mail Transfer Protocol
bftp            152/tcp                 # Background File Transfer Program
pftp            662/tcp                 # PFTP
dctp            675/tcp                 # DCTP
vatp            690/tcp                 # Velneo Application Transfer Protocol

Es importante que la expresión se indique con comillas simples, para evitar que sea interpretada indebidamente por Bash.

El operador corchetes permite indicar una secuencia implícita de caracteres. Por ejemplo, el operador [a-z] corresponde a cualquier letra del alfabeto, de a a z:

$ fdisk -l | grep '^Disco /dev/sd[a-z]'
Disco /dev/sda: 29,8 GiB, 32017047552 bytes, 62533296 sectores
Disco /dev/sdb: 298,1 GiB, 320072933376 bytes, 625142448 sectores
Disco /dev/sdc: 931,5 GiB, 1000170586112 bytes, 1953458176 sectores

El comando fdisk -l generó la información detalladas respecto de las particiones en los discos presentes en el sistema y envió a la entrada estándar de grep, que a su vez seleccionó solamente las lineas que comienzan con la palabra Disco seguidas de la ruta /dev/sd[a-z], correspondiente a cualquier ruta terminada con una letra del alfabeto.

El comando grep acepta diversas opciones que modifican su comportamiento. Algunas opciones comunes son:

Dos comandos complementan las funciones de grep: egrep y fgrep. El comando egrep es equivalente al comando grep -E, que incorpora otras funcionalidades además de las expresiones regulares patrón. Con egrep se puede usar el operador pipe, que actúa como el operador OU. De ese modo, la expresión 'invención|invenciones' corresponde a todas las ocurrencias del término invención o invenciones.

El comando fgrep actúa de la misma forma que grep -F, o sea, deja de interpretar expresiones regulares. Es especialmente útil en los casos más simples, cuando se quiere solamente localizar la ocurrencia de algún texto simple. Incluso si fueran utilizados caracteres especiales, como $ o el punto, estos serán interpretados literalmente, y no por el que representan una expresión regular.

Manipulando contenido de archivos

Existen muchos otros comandos que trabajan con archivos de texto, básicamente realizando tareas como recortar, extraer y filtrar. Varios de esos comandos son provistos por el paquete GNU coreutils.

El comando tac tiene la misma función de cat, pero muestra el contenido de atrás para adelante.

El comando sort ordena alfabéticamente. Con la opción -n, ordena numéricamente. La opción -r invierte el resultado.

El comando head muestra el comienzo de archivos. De manera predeterminada, se muestran las primeras diez lineas. La cantidad de lineas a ser mostradas se indica con la opción -n. La opción -c especifica el número de caracteres (bytes) a ser mostrados.

El comando tail muestra o final de archivos. De manera predeterminada, se muestran las últimas diez lineas. La cantidad de lineas a ser mostradas se indica con la opción -n. La opción -c especifica el número de caracteres (bytes) a ser mostrados. Para que el final del archivo sea mostrado continuamente, a medida que se agrega más texto, se usa la opción -f (de follow). El signo + indica que la lectura debe ser hecha a partir de la linea especificada después del +.

El comando wc cuenta lineas, palabras o caracteres, a partir de las opciones -l, -w y -c, respectivamente. Cuando se utiliza sin argumentos, muestra estos tres valores en la misma secuencia.

El comando cut delimita un archivo en columnas, en  determinado número de caracteres o por posición de campo. Para separar por campo, la opción -d especifica el carácter delimitador y -f informa la posición del campo. Por ejemplo, para mostrar los campos de la posición 1 y 3 del archivo /etc/group, que están separados por “:”:

$ cut -d ':' -f 1,3 /etc/group
root:0
daemon:1
bin:2
sys:3
adm:4
(...)

Para mostrar otro delimitador en lugar del original, se usa la opción --output-deilimiter:

$ cut -d ':' -f 1,3 --output-delimiter ' = ' /etc/group
root = 0
daemon = 1
bin = 2
sys = 3
adm = 4
(...)

El comando paste concatena archivos lado a lado, en forma de columnas:

$ cat uno.txt
1       a1      a2      a3
2       b1      b2      b3
3       c1      c2      c3

$ cat dos.txt
1       x1      x2      x3
2       y1      y2      y3
3       z1      z2      z3

$ paste uno.txt dos.txt
1       a1      a2      a3      1       x1      x2      x3
2       b1      b2      b3      2       y1      y2      y3
3       c1      c2      c3      3       z1      z2      z3

Todos estos comandos pueden ser combinados con canalizaciones y redireccionamientos. Aún cuando se utiliza un procesador de textos para editar un archivo, los comandos pueden ser útiles para realizar tareas más elaboradas o repetitivas.

3.3: Convertir comandos en un script

Peso: 4

Los scripts son archivos que actúan como programas, pasando instrucciones a un intérprete para realizar determinada tarea. A diferencia de los programas compilados, los scripts son archivos de texto que pueden ser manipulados en cualquier editor de texto puro. En Linux, es bastante común escribir shell scripts, que automatizan la ejecución de tareas en la línea de comando, de las más simples a las más sofisticadas. Cada línea del archivo script será interpretada como un comando digitado en el shell y debe respetar las mismas reglas de los comandos digitados manualmente.

Editores de texto

Existen diversos editores de texto para línea de comando. El más tradicional es vi, pero existen alternativas como pico y nano. Es recomendable conocer mínimamente vi, pues es el editor que se encuentra en cualquier ambiente Unix.

Edición con Vi

Vi es considerado un editor para usuarios experimentados. Incluso al compararlo con otros editores de terminal, sus peculiaridades lo tornan poco intuitivo para usuarios principiantes.

La interfaz de vi se resume a la pantalla donde se presenta y es manipulado el texto, con un cursor indicando donde se ejecuta la acción. Todas las operaciones son realizadas a partir de comandos del teclado. No vi existen los llamados modos de ejecución, en los cuales las acciones de teclado se comportan de manera distinta. Existen tres modos de ejecución básicos en vi: El modo de navegación, el modo de inserción y el o modo de comando.

El modo de navegación es el modo inicial de vi. En el las teclas del teclado actúan básicamente para navegación y selección de bloques de texto. Generalmente, los comandos son letras únicas. Si es precedido por un número, el comando será repetido correspondientemente al valor de ese número.

La utilización del modo de navegación sólo tiene sentido en un texto ya existente o luego de digitar algún contenido en un documento nuevo. Para abrir un archivo, basta brindar su ruta como argumento al comando vi. A continuación, algunos comandos de navegación importantes.

Diversas teclas de navegación pueden ser combinadas. Por ejemplo, para borrar todo el contenido a partir de la posición actual del cursor hasta el próximo punto, basta presionar las teclas dt..

La finalidad del modo de inserción es simplemente insertar texto. La tecla [Esc] sale del modo de inserción y regresa al modo de navegación.

El modo de comando es accionado al presionar la tecla : en el modo de navegación. Usado para hacer búsquedas, modificaciones, guardar, salir, ejecutar comandos en el shell, modificar la configuración de vi, etc. Para retornar al modo de navegación, se usa el comando visual o simplemente la tecla [Enter] con una línea vacía. A continuación, algunos comandos importantes del modo de comando:

Existen versiones de vi que poseen más recursos, como vim e incluso versiones con interfaz gráfica, como gvim. Sin embargo, vi es suficiente para escribir archivos de texto sin formato y scripts.

Inicio del script

La primera línea del archivo de script debe especificar el intérprete, que es indicado por los caracteres #! (termino conocido como she-bang). Para un script con instrucciones para el shell Bash, la primera línea deberá ser #!/bin/bash. Así, el intérprete para todas las instrucciones subsiguientes será el programa /bin/bash. Con excepción de la primera linea, todas las demás lineas que comienzan com # son ignoradas y pueden ser utilizadas como recordatorios y comentarios.

Variables especiales

Los argumentos pasados a un script y otras informaciones útiles son devueltas por la variable especial $x, en que x determina cual valor retornar:

Para solicitar valores al usuário durante la ejecución del script, se utiliza la instrución read:

echo "Informe valor solicitado:"
read RESPUESTA

El valor devuelto será almacenado en la variable RESPUESTA. En caso que una variable no sea especificada, se utilizará el nombre predeterminado de la variable, REPLY. Para almacenar la salida de un comando en una variable, se utilizan las comillas invertidas:

os=`uname -o`

Para mostrar el contenido de la variable, es necesario incluir el $ frente a su nombre. Las variables pueden ser utilizadas para mostrar valores o internamente, para almacenar datos que serán evaluados por el programa para la toma de decisiones.

Toma de decisiones

La principal característica de cualquier programa es la ejecución de determinadas acciones dependiendo de circunstancias preestablecidas. Para esta tarea, existe el operador if, que ejecuta un comando o una lista de comandos si una condición es verdadera. La instrucción test evalúa si la condición es verdadera o falsa. Su uso es generalmente asociado al operador if, como en el siguiente ejemplo, que muestra ok si el archivo /bin/bash es ejecutable:

if test -x /bin/bash ; then
  echo "ok"
fi

El siguiente ejemplo muestra otra manera de realizar la misma tarea:

if [ -x /bin/bash ] ; then
  echo "ok"
fi

La instrucción else es opcional para la estructura if y determina el bloque de instrucciones a ejecutar en caso que la afirmación evaluada sea falsa. Ejemplo:

if [ -x /bin/bash ] ; then
  echo "ok"
else
  echo "no ok"
fi

El final de la estructura if debe ser siempre indicado con fi.

Existen opciones de test para varias finalidades. A continuación, algunas opciones de evaluación de la instrucción test para archivos y directorios, suponiendo que la ruta de un archivo fue almacenada en la variable $ruta:

Opciones de evaluación de test para contenido de texto, suponiendo que la variable $texto contenga algún contenido:

Opções de avaliación de test para números, supondo que $num1 y $num2 contenham valores numéricos:

Una variación de la instrucción if es la instrucción case. La instrucción case proseguirá si un item indicado es encontrado en una lista de ítems separados por el carácter barra vertical “|”. Suponiendo que la variable $num contenga el número 3:

case $num in (1|2|3|4|5)
  echo "Número $num encontrado en la lista,";
  echo "por lo tanto case finalizó e";
  echo "ejecutó estos comandos";
esac

El final de la estrutura case debe ser siempre indicado con el término esac.

Instrucciones de repetición

Es bastante común el desarrollo de scripts cuya finalidad es  ejecutar determinada tarea repetidamente, obedeciendo a una condición preestablecida. Para ese fin existen las llamadas instrucciones de repetición o lazo.

La instrucción for ejecuta una o más acciones para cada elemento de una lista. En este caso, cada número generado por el comando seq:

for i in $(seq 5); del   echo "Copiando parte $i";
  scp daniel@epet1.edu.ar:~/parte_$i ./;
done

El comando seq 5 genera la secuencia numérica de 1 a 5, tomados de uno a uno por for y atribuidos a la variable i. Para cada item de la lista - en este caso, para cada número - será ejecutada la secuencia de comandos dentro del bloque hasta el término done.

La instrucción until ejecuta la secuencia de comandos hasta que una afirmación sea verdadera. Por ejemplo, implementar la misma repetición hecha anteriormente con for ahora con until:

i=1;
until [ $i -gt 5 ]; del   echo "Copiando parte $i";
  scp daniel@epet1.edu.ar:~/parte_$i ./;
  i=$(($i+1));
done

until generalmente es mayor que su equivalente en forpero,  puede ser más adecuado en algunas situaciones. Su criterio de cierre es más versátil que el contador del for, pues acepta cualquier parámetro del test.

La instrución while es semejante a la instrucción until, pero ejecuta una acción hasta que la afirmación deje de ser verdadera:

i=1;
while [ $i -le 5 ]; del   echo "Copiando parte $i";
  scp daniel@epet1.edu.ar:~/parte_$i ./;
  i=$(($i+1));
done

Este último ejemplo produce el mismo resultado de la implementación con until del ejemplo anterior.

Ejecución del script

En caso que el script vaya a ser compartido para que otros usuarios los ejecuten, es importante que tengan acesso de lectura al mismo. El script del Bash puede ser ejecutado invocando el comando bash teniendo la ruta del script como argumento. Por ejemplo, para ejecutar el script miscript.sh del directorio actual:

$ bash miscript.sh

Alternativamente, el script puede tener permiso de ejecución y ser ejecutado como un programa convencional. Para atribuir el permiso de ejecución a un script, se utiliza el comando chmod:

$ chmod +x miscript.sh

De esta forma, el archivo del script miscript.sh ubicado en el directorio actual podrá ser ejecutado directamente con el comando ./miscript.sh.