Я не уверен, что это лучше, чем делать это в памяти, но с тем, 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 pwhile печатает каждую строку в первом аргументе столько раз, сколько строк в этом файле - и его сценарий также передается в него через канал. Снова 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