Я не уверен, что это лучше, чем делать это в памяти, но с тем, sed
что r
убирает свой инфил для каждой строки в своем инфиле, а другой - по другую сторону канала, чередуя H
старое пространство с входными строками ...
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'
ВЫХОД
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
Я сделал это по-другому. Он хранит некоторые в памяти - он хранит строку вроде:
"$1" -
... для каждой строки в файле.
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"
}
Это очень быстро. Это cat
файл столько раз, сколько строк в файле |pipe
. С другой стороны канала этот вход объединяется с самим файлом столько раз, сколько строк в файле.
case
Материал только для портативности - yash
и zsh
как добавить один элемент к расколу, в то время как mksh
и posh
оба проигрывают один. ksh
, dash
, busybox
, И bash
все отщепляются точно так много полей , так как есть нули , как напечатано printf
. Как написано выше, результаты дают одинаковые результаты для каждой из вышеупомянутых оболочек на моей машине.
Если файл очень длинный, могут возникнуть $ARGMAX
проблемы со слишком большим количеством аргументов, и в этом случае вам нужно будет ввести xargs
или аналогичный.
Учитывая тот же вход, который я использовал до того, как выход идентичен. Но если бы я пошел больше ...
seq 10 10 10000 | nl -s, >/tmp/tmp
Это создает файл, почти идентичный тому, который я использовал ранее (без 'Row') - но в 1000 строк. Вы сами видите, как быстро это происходит:
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
При 1000 строках есть небольшие различия в производительности между оболочками - они bash
всегда самые медленные - но поскольку единственная работа, которую они выполняют, это генерирование строки arg (1000 копий filename -
), эффект минимален. Разница в производительности между zsh
- как указано выше - и bash
составляет сотую долю секунды здесь.
Вот еще одна версия, которая должна работать для файла любой длины:
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"
)
Он создает мягкую ссылку на свой первый аргумент /tmp
с полуслучайным именем, чтобы не зацикливаться на странных именах файлов. Это важно, потому что cat
арги передаются через канал xargs
. cat
Выходные данные сохраняются в <&3
то время как sed
p
while печатает каждую строку в первом аргументе столько раз, сколько строк в этом файле - и его сценарий также передается в него через канал. Снова paste
объединяет свои входные данные, но на этот раз он принимает только два аргумента -
для стандартного ввода и имени ссылки /dev/fd/3
.
Последнее - /dev/fd/[num]
ссылка - должно работать в любой системе linux и многих других, но если оно не создает именованный канал с mkfifo
использованием этого, вместо этого должно работать.
Последнее, что он делает, это rm
это мягкая ссылка, которую он создает перед выходом.
Эта версия на самом деле еще быстрее в моей системе. Я полагаю, это потому, что, хотя он исполняет больше приложений, он сразу же начинает передавать им их аргументы - тогда как прежде чем он сложил их все сначала
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