lunes, 20 de marzo de 2017

IFS

Normalmente, el shell realiza separación de palabras en la entrada proporcionada por read. Como hemos visto, esto significa que varias palabras separadas por uno o más espacios se convierten en elementos separados en la línea de entrada, y read las asigna a variables separadas. Este comportamiento lo configura una variable de shell llamada IFS (Internal Field Separator - Separador Interno de Campos). El valor por defecto de IFS contiene un espacio, un tabulador y un carácter de nueva línea, cada uno de los cuales separará unos elementos de otros.

Podemos ajustar el valor de IFS para controlar la separación de campos ingresados en read. Por ejemplo, el archivo /etc/passwd contiene líneas de datos que usan los dos puntos como separador de campos. Cambiando el valor de IFS a los dos puntos, podemos usar read para introducir contenido de /etc/passwd y separar campos correctamente en diferentes variables. Aquí tenemos un script que lo hace:

#!/bin/bash

# read-ifs: read fields from a file

FILE=/etc/passwd

read -p "Enter a username > " user_name

file_info=$(grep "^$user_name:" $FILE)

if [ -n "$file_info" ]; then
    IFS=":" read user pw uid gid name home shell <<< "$file_info"
    echo "User = '$user'"
    echo "UID = '$uid'"
    echo "GID = '$gid'"
    echo "Full Name = '$name'"
    echo "Home Dir. = '$home'"
    echo "Shell = '$shell'"
else
    echo "No such user '$user_name'" >&2
    exit 1
fi

Este script pide al usuario que introduzca el nombre de usuario de una cuenta del sistema, luego muestra los diferentes campos encontrados en el registro del usuario del archivo /etc/passwd. El script contiene dos líneas interesantes. La primera es:

file_info=$(grep "^$user_name:" $FILE)

Esta línea asigna el resultado del comando grep a la variable file_info. La expresión regular usada por grep garantiza que el nombre de usuario sólo conicidirá con una sola línea en el archivo /etc/passwd.

La segunda línea interesante es esta:

IFS=":" read user pw uid gid name home shell <<< "$file_info"

La línea consta de tres partes: una asignación de variable, un comando read con una lista de nombres de variables como argumentos, y un nuevo y extraño operador de redirección. Veremos la asignación de variables primero.

El shell permite que una o más asignaciones de variables se produzcan inmediatamente antes de un comando. Estas asignaciones alteran el entorno para el comando que les sigue. El efecto de la asignación es temporal; sólo cambian el entorno el tiempo que dura el comando. En nuestro caso, el valor de IFS se cambia al carácter dos puntos. Alternativamente, podríamos haber escrito el código así:

OLD_IFS="$IFS"
IFS=":"
read user pw uid gid name home shell <<< "$file_info"
IFS="$OLD_IFS"

donde almacenamos el valor de IFS, asignamos un nuevo valor, realizamos el comando read y luego restauramos IFS a su valor original. Claramente, colocar la asignación de variable delante del comando es una forma más concisa de hacer lo mismo.

El operador <<< indica una cadena-aquí (here string). Una cadena-aquí es como un documento-aquí, sólo que más corto, consistente en una única cadena. En nuestro ejemplo, la línea de datos del archivo /etc/passwd se pasa a la entrada estándar del comando read. Podríamos preguntarnos por qué elegimos este modo tan indirecto en lugar de:

echo "$file_info" | IFS=":" read user pw uid gid name home shell

Bueno, hay una razón...

No hay comentarios:

Publicar un comentario