¿Hay alguna manera de especificar múltiples variables (no solo enteros) en forbucles bash? Es posible que tenga 2 archivos que contienen texto arbitrario con el que necesitaría trabajar.
Lo que funcionalmente necesito es algo como esto:
for i in $(cat file1) and j in $(cat file2);do command $i $j;done
Primero, no lea las líneas con for , ya que existen varios problemas inevitables con la lectura de líneas mediante la división de palabras.
Suponiendo archivos de igual longitud, o si solo desea hacer un bucle hasta que se lean los dos archivos más cortos, es posible una solución simple.
while read -r x && read -r y <&3;do...done<file1 3<file2
Preparar una solución más general es difícil debido a que readdevuelve falso y varias otras razones. Este ejemplo puede leer un número arbitrario de secuencias y regresar después de la entrada más corta o más larga.
#!/usr/bin/env bash# Open the given files and assign the resulting FDs to arrName.# openFDs arrname file1 [file2 ...]
openFDs(){local x y i arr=$1
[[-v $arr ]]||return1
shift
for x;do{ exec {y}<"$x";}2>/dev/null ||return1
printf -v "${arr}[i++]"%d "$y"done}# closeFDs FD1 [FD2 ...]
closeFDs(){local x
for x;do
exec {x}<&-done}# Read one line from each of the given FDs and assign the output to arrName.# If the first argument is -l, returns false only when all FDs reach EOF.# readN [ -l ] arrName FD1 [FD2 ...]
readN(){if[[ $1 ==-l ]];thenlocal longest
shift
elselocal longest=filocal i x y status arr=$1
[[-v $arr ]]||return1
shift
for x;doif IFS= read -ru "$x""${arr}[i]"||{ unset -v "${arr}[i]";[[ ${longest+_}]]&&return1;};then
status=0fi((i++))donereturn ${status:-1}}# readLines file1 [file2 ...]
readLines(){local-a fds lines
trap 'closeFDs "${fds[@]}"' RETURN
openFDs fds "$@"||return1while readN -l lines "${fds[@]}";do
printf '%-1s '"${lines[@]}"
echo
done}{
readLines /dev/fd/{3..6}||{ echo 'error occured'>&2; exit 1;}}<<<$'a\nb\nc\nd'3<&0<<<$'1\n2\n3\n4\n5'4<&0<<<$'x\ny\nz'5<&0<<<$'7\n8\n9\n10\n11\n12'6<&0# vim: set fenc=utf-8 ff=unix ts=4 sts=4 sw=4 ft=sh nowrap et:
Entonces, dependiendo de si se readNobtiene -l, la salida es
a 1 x 7
b 2 y 8
c 3 z 9
d 41051112
o
a 1 x 7
b 2 y 8
c 3 z 9
Tener que leer múltiples transmisiones en un bucle sin guardar todo en múltiples matrices no es tan común. Si solo quieres leer matrices, deberías echarle un vistazo mapfile.
||no funciona para mi Procesa fichero1 continuación fichero2 , pero sí mantener los archivos sincronizados con la &&que sale del tiempo de bucle a primera EF . - GNU bash 4.1.5
Peter.O
No tuve un momento libre para probar, sí, probablemente querría ambos elementos por iteración. El ||operador de "lista" está en cortocircuito como en la mayoría de los idiomas. Seguramente esto ha sido respondido mil veces antes ...
ormaaj
El punto no es la frecuencia con que frecuencia se ha mencionado algo antes. Más bien, es que el código que está mostrando actualmente en su respuesta no funciona . Según su " probablemente desee ambos elementos ...", parece que aún no lo ha probado.
Peter.O
@ Peter.O lo sé. Ha sido arreglado.
ormaaj
2
Hacer hecho; hecho: necesita dos fors y dos dones:
for i in $(< file1);dofor j in $(< file2);do echo $i $j;done;done
El archivo2, por supuesto, se procesa para cada palabra en el archivo1 una vez.
Usar <en lugar de cat debería ser una ganancia de rendimiento sin complicaciones en la mayoría de los casos. No hay subproceso involucrado. (No estoy seguro acerca de la última oración).
Sin comprimir:
for i in $(< file1)dofor j in $(< file2)do
echo $i $j
donedone
Si no le gusta leer palabras, sino líneas, y preservar el espacio en blanco, use while y lea:
while read line;dowhile read second;do echo "${line}${second}";done<file2 ;done<file1
Dices que no hay ningún subproceso invocado. ¿No es el () un subshell? No quiero ser pendante, pero no estoy seguro de lo que está sucediendo ahora. Por ejemplo, sé que cuando tengo un script y no quiero que contamine el shell actual con cd's, por ejemplo, lo hago dentro de un (). También en ejecución (suspensión 4) y, por ejemplo, seguido de una ps me muestra que el proceso aún se está ejecutando. ¿Puedes por favor elaborar?
Silverrocker
Bueno, lo siento, estoy actuando sin fundamento aquí. Pensé que lo escuché así, pero tal vez sea solo en <comparación con cat. Y no estoy seguro de cómo probarlo y cuándo será semánticamente importante. Si se invocan tuberías, las variables en los subprocesos no aparecen en el proceso principal, pero aquí no tenemos variables. Golpeo la oración crítica, hasta que alguien pueda aclararla.
Usuario desconocido
0
whiletiene una sintaxis interesante. Puede poner varios comandos antes del do ... whileciclo, y el caso en cuestión puede necesitar hacer malabares con esta función, dependiendo de sus requisitos particulares de: ¿lee al final del archivo más largo o solo al final del más corto?
Por ejemplo, read || readsimplemente no funciona (según los requisitos de la pregunta), porque cuando se lee el primer archivo true, se omite la lectura del segundo archivo hasta que se haya leído el primer archivo de principio a fin ... Luego, porque el estado aún así true, el ciclo while continúa y lee el segundo archivo de principio a fin.
read && readleerá los archivos simultáneamente (sincrónicamente) si solo desea leer hasta el archivo más corto. Sin embargo, si desea leer ambos archivos eof, debe trabajar con los while'srequisitos de sintaxis, es decir. por el comando inmediatamente antes del do whileciclo que produce un código de retorno distinto de cero para salir del ciclo while.
Aquí hay un ejemplo de cómo leer ambos archivos en eof
||
no funciona para mi Procesa fichero1 continuación fichero2 , pero sí mantener los archivos sincronizados con la&&
que sale del tiempo de bucle a primera EF . - GNU bash 4.1.5||
operador de "lista" está en cortocircuito como en la mayoría de los idiomas. Seguramente esto ha sido respondido mil veces antes ...Hacer hecho; hecho: necesita dos fors y dos dones:
El archivo2, por supuesto, se procesa para cada palabra en el archivo1 una vez.
Usar <en lugar de cat debería ser una ganancia de rendimiento sin complicaciones en la mayoría de los casos.
No hay subproceso involucrado.(No estoy seguro acerca de la última oración).Sin comprimir:
Si no le gusta leer palabras, sino líneas, y preservar el espacio en blanco, use while y lea:
Si desea agregar 2 archivos y no anidarlos:
Si desea comprimir 2 archivos, use pegar:
fuente
<
comparación concat
. Y no estoy seguro de cómo probarlo y cuándo será semánticamente importante. Si se invocan tuberías, las variables en los subprocesos no aparecen en el proceso principal, pero aquí no tenemos variables. Golpeo la oración crítica, hasta que alguien pueda aclararla.while
tiene una sintaxis interesante. Puede poner varios comandos antes deldo ... while
ciclo, y el caso en cuestión puede necesitar hacer malabares con esta función, dependiendo de sus requisitos particulares de: ¿lee al final del archivo más largo o solo al final del más corto?Por ejemplo,
read || read
simplemente no funciona (según los requisitos de la pregunta), porque cuando se lee el primer archivotrue
, se omite la lectura del segundo archivo hasta que se haya leído el primer archivo de principio a fin ... Luego, porque el estado aún asítrue
, el ciclo while continúa y lee el segundo archivo de principio a fin.read && read
leerá los archivos simultáneamente (sincrónicamente) si solo desea leer hasta el archivo más corto. Sin embargo, si desea leer ambos archivoseof
, debe trabajar con loswhile's
requisitos de sintaxis, es decir. por el comando inmediatamente antes deldo while
ciclo que produce un código de retorno distinto de cero para salir del ciclo while.Aquí hay un ejemplo de cómo leer ambos archivos en eof
(es posible que desee probar eof3 y eof4 antes de la lectura, pero la idea general está ahí, especialmente en la condición final verdadero / falso.
fuente