Я не впевнений, що це краще, ніж робити це в пам’яті, але з тим, 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файл стільки разів, скільки є файлів у файлі a |pipe. З іншого боку труби, що вводиться, об'єднується з самим файлом стільки разів, скільки є файли у файлі.
caseМатеріал тільки для портативності - yashі zshяк додати один елемент до розколу, в той час як mkshі poshобидва програють один. ksh, dash, busybox, І bashвсе отщепляются точно так багато полів , так як є нулі , як надруковано printf. Як написано вище, це дає однакові результати для кожної з вищезазначених снарядів на моїй машині.
Якщо файл дуже довгий, можуть виникнути $ARGMAXпроблеми із занадто великою кількістю аргументів, і в цьому випадку вам також потрібно буде ввести xargsабо подібні.
З огляду на той же вхід, який я використовував до виходу ідентичний. Але, якби я став більшим ...
seq 10 10 10000 | nl -s, >/tmp/tmp
Це генерує файл, майже ідентичний тому, що я використовував раніше (sans '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це незмінно найповільніше - але тому, що єдиною роботою, яку вони роблять, все-таки є генерування рядка аргументу (1000 копій filename -), ефект мінімальний. Різниця в продуктивності між zsh- як вище - і bashстановить 100-ту секунду.
Ось ще одна версія, яка повинна працювати для файлу будь-якої довжини:
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записує кожен рядок у першому аргументі стільки разів, скільки є рядки у цьому файлі - і його сценарій також подається на нього через трубу. Знову 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