Я не впевнений, що це краще, ніж робити це в пам’яті, але з тим, 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