bash – Cómo leer de dos archivos de entrada usando while loop

Pregunta:

Quería saber si hay alguna forma de leer de dos archivos de entrada en un ciclo while anidado una línea a la vez. Por ejemplo, digamos que tengo dos archivos FileA y FileB .

Presentar un:

[jaypal:~/Temp] cat filea
this is File A line1
this is File A line2
this is File A line3

ArchivoB:

[jaypal:~/Temp] cat fileb
this is File B line1
this is File B line2
this is File B line3

Script de muestra actual:

[jaypal:~/Temp] cat read.sh 
#!/bin/bash
while read lineA
    do echo $lineA 
    while read lineB
        do echo $lineB 
        done < fileb
done < filea

Ejecución:

[jaypal:~/Temp] ./read.sh 
this is File A line1
this is File B line1
this is File B line2
this is File B line3
this is File A line2
this is File B line1
this is File B line2
this is File B line3
this is File A line3
this is File B line1
this is File B line2
this is File B line3

Problema y resultado deseado:

Esto recorre FileB completamente para cada línea en FileA. Intenté usar continue, break, exit pero ninguno de ellos está destinado a lograr el resultado que estoy buscando. Me gustaría que el script lea solo una línea del Archivo A y luego una línea del Archivo B y salga del bucle y continúe con la segunda línea del Archivo A y la segunda línea del Archivo B. Algo similar al siguiente script:

[jaypal:~/Temp] cat read1.sh 
#!/bin/bash
count=1
while read lineA
    do echo $lineA 
        lineB=`sed -n "$count"p fileb`
        echo $lineB
        count=`expr $count + 1`
done < filea

[jaypal:~/Temp] ./read1.sh 
this is File A line1
this is File B line1
this is File A line2
this is File B line2
this is File A line3
this is File B line3

¿Es posible lograr esto con el bucle while?

Respuesta:

Si puede garantizar que nunca aparecerá algún carácter en el primer archivo, puede usar pegar.

Por ejemplo, sabe con certeza que @ nunca ocurrirá:

paste -d@ file1 file2 | while IFS="@" read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done

Tenga en cuenta que es suficiente si se garantiza que el carácter no aparecerá en el primer archivo. Esto se debe a que read ignorará IFS al completar la última variable. Entonces, incluso si aparece @ en el segundo archivo, no se dividirá.

Ejemplo usando algunas características de bash para un código posiblemente más limpio y pegado usando la pestaña delimitador predeterminada:

while IFS=$'\t' read -r f1 f2
do
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done < <(paste file1 file2)

Funciones de bash utilizadas: cadena ansi c ( $'\t' ) y sustitución de proceso ( <(...) ) para evitar el bucle while en un problema de subcapa .

Si no puede estar seguro de que ningún carácter aparecerá en ambos archivos, puede utilizar dos descriptores de archivo .

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  printf 'f1: %s\n' "$f1"
  printf 'f2: %s\n' "$f2"
done 3<file1 4<file2

No probado mucho. Podría romperse en líneas vacías.

Los descriptores de archivo número 0, 1 y 2 ya se utilizan para stdin, stdout y stderr, respectivamente. Los descriptores de archivo de 3 en adelante son (generalmente) gratuitos. El manual de bash advierte sobre el uso de descriptores de archivos superiores a 9, porque se "utilizan internamente".

Tenga en cuenta que los descriptores de archivos abiertos se heredan a funciones de shell y programas externos. Las funciones y programas que heredan un descriptor de archivo abierto pueden leer (y escribir) en el descriptor de archivo. Debe tener cuidado de cerrar todos los descriptores de archivos que no sean necesarios antes de llamar a una función o programa externo.

Aquí está el mismo programa que el anterior con el trabajo real (la impresión) separado del meta-trabajo (leyendo línea por línea de dos archivos en paralelo).

work() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  work "$f1" "$f2"
done 3<file1 4<file2

Ahora pretendemos que no tenemos control sobre el código de trabajo y ese código, por la razón que sea, intenta leer desde el descriptor de archivo 3.

unknowncode() {
  printf 'f1: %s\n' "$1"
  printf 'f2: %s\n' "$2"
  read -r yoink <&3 && printf 'yoink: %s\n' "$yoink"
}

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  unknowncode "$f1" "$f2"
done 3<file1 4<file2

A continuación se muestra un resultado de ejemplo. Tenga en cuenta que la segunda línea del primer archivo es "robada" del bucle.

f1: file1 line1
f2: file2 line1
yoink: file1 line2
f1: file1 line3
f2: file2 line2

Así es como debe cerrar los descriptores de archivo antes de llamar a un código externo (o cualquier código para el caso).

while true
do
  read -r f1 <&3 || break
  read -r f2 <&4 || break
  # this will close fd3 and fd4 before executing anycode
  anycode "$f1" "$f2" 3<&- 4<&-
  # note that fd3 and fd4 are still open in the loop
done 3<file1 4<file2

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top

web tasarım