viernes, 21 de agosto de 2009

Leer multiples archivos con Bash

Leer archivos en bash no es algo complicado, solo redireccionas la salida del comando o unes con otro comando o podrías hacerlo dentro del código si el nombre de los archivos esta predeterminados. Puedes usar el proceso de substitución para pasar los archivos abiertos desde la linea de comando. Otra opción es simplemente abrir los archivos y leerlos como quieras, tal como harías en otros lenguajes de programación.

El mecanismo que se usara toma ventaja de la habilidad de bash para redireccionar la salida usando un descriptor de archivo con la siguiente sintaxis:

n<archivo

n>>archivo
n<>archivo

La "n" vendría a ser un numero entero que especifica el descriptor de archivo para usarlo para abrir el archivo nombrado. Si no se especifica "n" entonces aplicaría lo siguiente por defecto:

<archivo     # igual que 1>archivo

>>archivo # igual que 1>>archivo
<>archivo # igual que 0<>archivo

Por supuesto esto es el estándar para redireccionar que se usa todas las veces.

Entonces, dado que "n" esta ahi, parecería que uno podría abrir fácilmente los archivos que necesita y procesarlos. Como se hace actualmente quizás es menos que obvio, pero en realidad es algo simple:

exec 7exec 8

Esto abre el archivo1 en el descriptor 7 para entrada y el archivo2 en el descriptor 8. Ahora se pueden leer fácilmente:

read data1 <&7

read data2 <&8

Nota que la redireccion de entrada para leer usa una forma especial que incluye un ampersand (&) para especificar que lo que sigue es un descriptor y no un nombre de archivo.

Usa los descriptores en el rango de 3-9. Los descriptores que pertenecen a 3 son usados para entradas estándar, salida y error, los que están arriba de 9 pueden ser usados internamente por el shell.

A pesar de que no hay una sintaxis especifica para cerrar el archivo, al re-usar el descriptor se cerrara el archivo antes de que se abra uno nuevo. Para estar seguro puedes usar lo siguiente para cerrar los archivos:

exec 7exec 8

La razón del exec es que el abrir los archivos se hace en el shell actual y no en el sub-shell, lo cual cerraría el descriptor tan pronto el comando complete.

Un ejemplo de como hacer eso es el siguiente:


#!/bin/bash

function readfiles()
{
local FD1=7
local FD2=8
local file1=$1
local file2=$2
local count1=0
local count2=0
local eof1=0
local eof2=0
local data1
local data2

# Open files.
exec 7<$file1
exec 8<$file2
while [[ $eof1 -eq 0 || $eof2 -eq 0 ]]
do
if read data1 <&$FD1; then
let count1++
printf "%s, line %d: %s\n" $file1 $count1 "$data1"
else
eof1=1
fi
if read data2 <&$FD2; then
let count2++
printf "%s, line %d: %s\n" $file2 $count2 "$data2"
else
eof2=1
fi
done }
echo "Reading file1 and file2" readfiles file1 file2
echo "Reading file3 and file4" readfiles file3 file4
# vim: tabstop=4: shiftwidth=4: noexpandtab:
# kate: tab-width 4; indent-width 4; replace-tabs false;


La función de arriba lee los archivos, el código principal procesa dos archivos, luego procesa 2 archivos diferentes. El comando produce lo siguiente:

$ bash readmult.sh
Reading file1 and file2
file1, line 1: f1 line 1
file2, line 1: f2 line 1
file1, line 2: f1 line 2
file2, line 2: f2 line 2
file1, line 3: f1 line 3
file2, line 3: f2 line 3
file1, line 4: f1 line 4
file2, line 4: f2 line 4
file1, line 5: f1 line 5
file2, line 5: f2 line 5
file1, line 6: f1 line 6
Reading file3 and file4
file3, line 1: f3 line 1
file4, line 1: f4 line 1
file3, line 2: f3 line 2
file4, line 2: f4 line 2
file3, line 3: f3 line 3

Un proceso similar puede ser usado para escribir múltiples archivos usando n>archivo o n>> archivo. Algo para ahorrar tiempo si estas escribiendo mucha información al mismo archivo en varios lugares diferentes de tu código.

Leido en LinuxJournal.

No hay comentarios: