Não tenho certeza se isso é melhor do que fazê-lo na memória, mas com um sedque rpreenche seu infile para cada linha em seu infile e outro no outro lado de um tubo alternando o Hespaço antigo com as linhas 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'
RESULTADO
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
Eu fiz isso de outra maneira. Ele armazena um pouco na memória - armazena uma string como:
"$1" -
... para cada linha no arquivo.
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"
}
É muito rápido. É cato arquivo quantas vezes houver linhas no arquivo para a |pipe. No outro lado do canal, essa entrada é mesclada com o próprio arquivo quantas vezes houver linhas no arquivo.
O casematerial é apenas para portabilidade - yashe zshtanto um elemento de adicionar à divisão, enquanto mkshe poshtanto um perder. ksh, dash, busybox, E bashtudo dividido para exatamente quantos campos existem zeros como impressa pelo printf. Conforme escrito, o acima apresenta os mesmos resultados para cada uma das conchas acima mencionadas na minha máquina.
Se o arquivo for muito longo, poderá haver $ARGMAXproblemas com muitos argumentos; nesse caso, você precisará introduzir xargsou similar também.
Dada a mesma entrada que usei antes da saída é idêntica. Mas se eu fosse maior ...
seq 10 10 10000 | nl -s, >/tmp/tmp
Isso gera um arquivo quase idêntico ao que eu usei antes (sans 'Row') - mas com 1000 linhas. Você pode ver por si mesmo o quão rápido é:
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
Em 1000 linhas, há uma ligeira variação no desempenho entre os shells - bashé invariavelmente o mais lento - mas como o único trabalho que eles fazem é gerar a string arg (1000 cópias filename -), o efeito é mínimo. A diferença de desempenho entre zsh- como acima - e bashé centésimo de segundo aqui.
Aqui está outra versão que deve funcionar para um arquivo de qualquer tamanho:
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"
)
Ele cria um link suave para o seu primeiro argumento /tmpcom um nome semi-aleatório, para que não fique preso a nomes de arquivos estranhos. Isso é importante porque catos argumentos são alimentados através de um cano via xargs. catA saída do arquivo é salva <&3enquanto sed pas linhas do primeiro argumento são copiadas quantas vezes houver linhas nesse arquivo - e seu script também é alimentado por meio de um pipe. Novamente pastemescla sua entrada, mas desta vez são necessários apenas dois argumentos -novamente para sua entrada padrão e o nome do link /dev/fd/3.
Esse último - o /dev/fd/[num]link - deve funcionar em qualquer sistema Linux e muito mais, mas se não criar um pipe nomeado mkfifoe usá-lo, também funcionará.
A última coisa que ele faz é rmo link direto criado antes de sair.
Esta versão é realmente mais rápida ainda no meu sistema. Eu acho que é porque, apesar de executar mais aplicativos, ele começa a entregar seus argumentos imediatamente - enquanto antes os empilhava primeiro.
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