Nie jestem pewien, czy jest to lepsze niż robienie tego w pamięci, ale z tym, sed
który r
oddziela swój infile dla każdej linii w swoim infile i innym po drugiej stronie potoku na przemian ze H
starą przestrzenią z liniami wejściowymi ...
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'
WYNIK
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
Zrobiłem to w inny sposób. Przechowuje niektóre elementy w pamięci - przechowuje ciąg taki jak:
"$1" -
... dla każdej linii w pliku.
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"
}
To jest bardzo szybkie. Jest cat
to plik tyle razy, ile jest linii w pliku do |pipe
. Po drugiej stronie potoku dane wejściowe są scalane z samym plikiem tyle razy, ile jest linii w pliku.
case
Rzeczy jest właśnie dla przenośności - yash
i zsh
zarówno dodatek jeden element do rozłamu, podczas mksh
i posh
zarówno stracić. ksh
, dash
, busybox
, I bash
wszystko podzielonego się dokładnie tak, jak wielu dziedzinach jak istnieją zera podany przez printf
. Jak napisano powyżej, renderuje takie same wyniki dla każdej z wyżej wymienionych powłok na moim komputerze.
Jeśli plik jest bardzo długi, mogą występować $ARGMAX
problemy ze zbyt dużą liczbą argumentów, w którym to przypadku należy wprowadzić xargs
lub podobne.
Biorąc pod uwagę to samo wejście, którego użyłem przed wyjściem jest identyczne. Ale gdybym miał zwiększyć ...
seq 10 10 10000 | nl -s, >/tmp/tmp
To generuje plik prawie identyczny z tym, którego użyłem wcześniej (bez wiersza) - ale w 1000 linii. Możesz sam przekonać się, jak szybko to jest:
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
Przy 1000 liniach występuje niewielka różnica w wydajności między powłokami - bash
jest niezmiennie najwolniejsza - ale ponieważ jedyną pracą, którą wykonują, jest generowanie ciągu arg (1000 kopii filename -
), efekt jest minimalny. Różnica w wydajności między zsh
- jak wyżej - i bash
wynosi tutaj setną sekundy.
Oto kolejna wersja, która powinna działać dla pliku o dowolnej długości:
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"
)
Tworzy miękkie łącze do pierwszego argumentu /tmp
z pół losową nazwą, aby nie rozłączać się z dziwnymi nazwami plików. To ważne, ponieważ cat
argony są podawane do niego za pośrednictwem rury za pośrednictwem xargs
. cat
„s wyjście jest zapisywany <&3
podczas sed
p
rints każdy wiersz w pierwszej arg tyle razy, ile jest linii w tym pliku - a jej scenariusz jest także podawany do niego rurą. Ponownie paste
łączy dane wejściowe, ale tym razem wymaga tylko dwóch argumentów -
dla standardowego wejścia i nazwy łącza /dev/fd/3
.
To ostatnie - /dev/fd/[num]
link - powinno działać na każdym systemie linux i wielu innych oprócz, ale jeśli nie tworzy nazwanego potoku mkfifo
i używanie go zamiast tego powinno również działać.
Ostatnią rzeczą, jaką robi, jest rm
miękkie łącze, które tworzy przed wyjściem.
Ta wersja jest jeszcze szybsza w moim systemie. Wydaje mi się, że dzieje się tak, ponieważ chociaż uruchamia więcej aplikacji, natychmiast przekazuje im swoje argumenty - a zanim najpierw ułożył je wszystkie w stos.
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