No estoy seguro de que esto sea mejor que hacerlo en la memoria, pero con un sed
que r
borra su archivo para cada línea en su archivo y otro en el otro lado de una tubería que alterna el H
espacio antiguo con líneas de entrada ...
cat <<\IN >/tmp/tmp
Row1,10
Row2,20
Row3,30
Row4,40
IN
</tmp/tmp sed -e 'i\
' -e 'r /tmp/tmp' |
sed -n '/./!n;h;N;/\n$/D;G;s/\n/ /;P;D'
SALIDA
Row1,10 Row1,10
Row1,10 Row2,20
Row1,10 Row3,30
Row1,10 Row4,40
Row2,20 Row1,10
Row2,20 Row2,20
Row2,20 Row3,30
Row2,20 Row4,40
Row3,30 Row1,10
Row3,30 Row2,20
Row3,30 Row3,30
Row3,30 Row4,40
Row4,40 Row1,10
Row4,40 Row2,20
Row4,40 Row3,30
Row4,40 Row4,40
Hice esto de otra manera. Almacena algunos en la memoria, almacena una cadena como:
"$1" -
... para cada línea en el archivo.
pairs(){ [ -e "$1" ] || return
set -- "$1" "$(IFS=0 n=
case "${0%sh*}" in (ya|*s) n=-1;; (mk|po) n=+1;;esac
printf '"$1" - %s' $(printf "%.$(($(wc -l <"$1")$n))d" 0))"
eval "cat -- $2 </dev/null | paste -d ' \n' -- $2"
}
Es muy rápido. Es cat
el archivo tantas veces como haya líneas en el archivo a |pipe
. En el otro lado de la tubería, esa entrada se fusiona con el archivo en sí tantas veces como haya líneas en el archivo.
El case
material es sólo para la portabilidad - yash
y zsh
tanto un elemento añadir a la división, mientras mksh
y posh
tanto uno perder. ksh
, dash
, busybox
, Y bash
toda división a cabo exactamente como muchos campos, ya que hay ceros como impreso por printf
. Como está escrito, lo anterior genera los mismos resultados para cada uno de los shells mencionados anteriormente en mi máquina.
Si el archivo es muy largo, puede haber $ARGMAX
problemas con demasiados argumentos, en cuyo caso necesitaría introducir xargs
o similar también.
Dada la misma entrada que usé antes de que la salida sea idéntica. Pero, si fuera más grande ...
seq 10 10 10000 | nl -s, >/tmp/tmp
Eso genera un archivo casi idéntico al que usé antes (sin 'Fila') , pero con 1000 líneas. Puedes ver por ti mismo lo rápido que es:
time pairs /tmp/tmp |wc -l
1000000
pairs /tmp/tmp 0.20s user 0.07s system 110% cpu 0.239 total
wc -l 0.05s user 0.03s system 32% cpu 0.238 total
A 1000 líneas hay una ligera variación en el rendimiento entre los shells, bash
es invariablemente el más lento, pero debido a que el único trabajo que hacen de todos modos es generar la cadena arg (1000 copias de filename -
) el efecto es mínimo. La diferencia en el rendimiento entre zsh
- como arriba - y bash
es la centésima de segundo aquí.
Aquí hay otra versión que debería funcionar para un archivo de cualquier longitud:
pairs2()( [ -e "$1" ] || exit
rpt() until [ "$((n+=1))" -gt "$1" ]
do printf %s\\n "$2"
done
[ -n "${1##*/*}" ] || cd -P -- "${1%/*}" || exit
: & set -- "$1" "/tmp/pairs$!.ln" "$(wc -l <"$1")"
ln -s "$PWD/${1##*/}" "$2" || exit
n=0 rpt "$3" "$2" | xargs cat | { exec 3<&0
n=0 rpt "$3" p | sed -nf - "$2" | paste - /dev/fd/3
}; rm "$2"
)
Crea un enlace suave a su primer argumento /tmp
con un nombre semi-aleatorio para que no se obsesione con nombres de archivos extraños. Eso es importante porque cat
los args se alimentan a través de una tubería xargs
. cat
La salida de se guarda en <&3
mientras sed
p
borra cada línea en el primer argumento tantas veces como haya líneas en ese archivo, y su script también se alimenta a través de una tubería. Nuevamente paste
fusiona su entrada, pero esta vez solo toma dos argumentos -
nuevamente para su entrada estándar y el nombre del enlace /dev/fd/3
.
Ese último, el /dev/fd/[num]
enlace, debería funcionar en cualquier sistema Linux y muchos más, pero si no crea una tubería con nombre mkfifo
y usarlo, también debería funcionar.
Lo último que hace es rm
el enlace suave que crea antes de salir.
Esta versión es realmente más rápida aún en mi sistema. Supongo que es porque aunque ejecuta más aplicaciones, comienza a entregarles sus argumentos de inmediato, mientras que antes los apilaba primero.
time pairs2 /tmp/tmp | wc -l
1000000
pairs2 /tmp/tmp 0.30s user 0.09s system 178% cpu 0.218 total
wc -l 0.03s user 0.02s system 26% cpu 0.218 total