Установите переменную среды CVSEDITOR
Вашему любимому редактору. Это не расширено оболочкой, таким образом, тильда не будет работать. Так запишите короткую обертку оболочки и призовите это CVSEDITOR
. Запишите это как ~/bin/CVSEDITOR
и сделайте это исполняемым файлом:
#!/bin/sh
exec vim -S ~/myscript.vim
Затем вставьте следующую строку Ваш ~/.profile
:
export CVSEDITOR=CVSEDITOR
Если Вы хотите использовать того же редактора для всего, установите EDITOR
и VISUAL
переменные вместо этого (устанавливает оба на то же значение).
Я предлагаю sed
решение, но ради полноты,
awk 'NR >= 57890000 && NR <= 57890010' /path/to/file
Отключать после последней строки:
awk 'NR < 57890000 { next } { print } NR == 57890010 { exit }' /path/to/file
Тест скорости (здесь на macOS, YMMV в других системах):
seq 100000000 > test.in
real
время, как сообщается bash
встроенный time
4.373 4.418 4.395 tail -n+50000000 test.in | head -n10
5.210 5.179 6.181 sed -n '50000000,50000010p;57890010q' test.in
5.525 5.475 5.488 head -n50000010 test.in | tail -n10
8.497 8.352 8.438 sed -n '50000000,50000010p' test.in
22.826 23.154 23.195 tail -n50000001 test.in | head -n10
25.694 25.908 27.638 ed -s test.in <<<"50000000,50000010p"
31.348 28.140 30.574 awk 'NR<57890000{next}1;NR==57890010{exit}' test.in
51.359 50.919 51.127 awk 'NR >= 57890000 && NR <= 57890010' test.in
Это ни в коем случае не точные сравнительные тесты, но различие является четким и достаточно повторяемое* для предоставления хорошего чувства относительной скорости каждой из этих команд.
*: Кроме между первыми двумя, sed -n p;q
и head|tail
, которые, кажется, по существу то же.
Если Вы хотите строки X к Y включительно (начинающий нумерацию в 1), использовать
tail -n "+$X" /path/to/file | head -n "$((Y-X+1))"
tail
считает и отбросит первые X-1 строки (нет никакого пути вокруг того), затем считайте и распечатайте следующие строки. head
считает и распечатает требуемое количество строк, затем выйдет. Когда head
выходы, tail
получает сигнал SIGPIPE и умирает, таким образом, он не будет читать больше, чем ценность размера буфера (обычно несколько килобайтов) строк из входного файла.
С другой стороны, как gorkypl предложенный, используйте sed:
sed -n -e "$X,$Y p" -e "$Y q" /path/to/file
sed решение значительно медленнее хотя (по крайней мере, для утилит GNU и утилит Busybox; sed мог бы быть более конкурентоспособным при извлечении значительной части файла на ОС, где передача по каналу является медленной, и sed быстр). Вот быстрые сравнительные тесты в соответствии с Linux; данные были сгенерированы seq 100000000 >/tmp/a
, среда является Linux/amd64, /tmp
tmpfs, и машина в других отношениях неактивна и не подкачивает.
real user sys command
0.47 0.32 0.12 </tmp/a tail -n +50000001 | head -n 10 #GNU
0.86 0.64 0.21 </tmp/a tail -n +50000001 | head -n 10 #BusyBox
3.57 3.41 0.14 sed -n -e '50000000,50000010 p' -e '50000010q' /tmp/a #GNU
11.91 11.68 0.14 sed -n -e '50000000,50000010 p' -e '50000010q' /tmp/a #BusyBox
1.04 0.60 0.46 </tmp/a tail -n +50000001 | head -n 40000001 >/dev/null #GNU
7.12 6.58 0.55 </tmp/a tail -n +50000001 | head -n 40000001 >/dev/null #BusyBox
9.95 9.54 0.28 sed -n -e '50000000,90000000 p' -e '90000000q' /tmp/a >/dev/null #GNU
23.76 23.13 0.31 sed -n -e '50000000,90000000 p' -e '90000000q' /tmp/a >/dev/null #BusyBox
Если Вы знаете диапазон байта, Вы хотите работать с, можно извлечь его быстрее путем пропуска непосредственно к позиции запуска. Но для строк, необходимо читать с начала и считать новые строки. Извлечь блоки из x включительно к y эксклюзивному запуску в 0, с размером блока b:
dd bs="$b" seek="$x" count="$((y-x))" </path/to/file
tail will read and discard the first X-1 line
кажется, избегают, когда количество строк дано от конца В таком случае, хвост, кажется, читает назад от конца согласно выполняющимся временам. Читайте: http://unix.stackexchange.com/a/216614/79743
.
–
17.07.2015, 07:52
tail
(включая хвост GNU), имеют эвристику для чтения из конца. Это улучшается tail | head
решение по сравнению с другими методами.
– Gilles 'SO- stop being evil'
17.07.2015, 10:08
Самый православный путь (но не самое быстрое, как отмечено Gilles выше) состоял бы в том, чтобы использовать sed
.
В Вашем случае:
X=57890000
Y=57890010
sed -n -e "$X,$Y p" -e "$Y q" filename
-n
опция подразумевает, что только соответствующие строки печатаются к stdout.
P в конце числа финишной черты означает печатать строки в данном диапазоне. Q во второй части сценария экономит некоторое время путем пропуска остатка от файла.
sed
и tail | head
чтобы быть о наравне, но это оказывается этим tail | head
значительно быстрее (см. мой ответ).
– Gilles 'SO- stop being evil'
08.09.2012, 14:31
tail
/head
считаются более "православными", начиная с обрезки любого конца файла точно, для чего они сделаны. В тех материалах, sed
только, кажется, вводит изображение, когда замены требуются - и быстро быть продвинутыми из изображения, когда что-либо, намного более сложные запуски для случая так как его синтаксис для сложных задач настолько хуже, чем AWK, который затем вступает во владение.
– underscore_d
08.10.2016, 14:40
head | tail
подход является одним из лучших и большинства "идиоматических" способов сделать это:
X=57890000
Y=57890010
< infile.txt head -n "$Y" | tail -n +"$X"
Как указано Gilles в комментариях, более быстрый путь
< infile.txt tail -n +"$X" | head -n "$((Y - X))"
Причиной это быстрее, является первое X - 1 строка не должна проходить канал по сравнению с head | tail
подход.
Ваш вопрос, как формулируется является немного вводящим в заблуждение и вероятно объясняет некоторые Ваши необоснованные опасения к этому подходу.
Вы говорите, что необходимо вычислить A
, B
, C
, D
но как Вы видите, количество строки файла не нужно, и самое большее 1 вычисление необходимо, который оболочка может сделать для Вас так или иначе.
Вы волнуетесь, что передача по каналу считает больше строк, чем необходимый. На самом деле это не верно: tail | head
почти так эффективно, как можно добраться с точки зрения файлового ввода-вывода. Во-первых, считайте минимальный объем работы необходимым: для нахождения строки X'th в файле единственный общий способ сделать это состоит в том, чтобы считать каждый байт и остановку когда Вы символы новой строки количества X, поскольку нет никакого способа предугадать файловое смещение строки X'th. После того как Вы достигаете *строка X*th, необходимо считать все строки для печати их, остановившись в строке Y'th. Таким образом никакому подходу не может сойти с рук чтение меньше, чем строки Y. Теперь, head -n $Y
чтения не больше, чем Y строки (округленный к ближайшей буферной единице, но буферам, если используется правильно улучшают производительность, таким образом, никакая потребность волноваться о тех издержках). Кроме того, tail
не будет больше читать, чем head
, таким образом, таким образом мы показали это head | tail
наименьшее количество чтений нумерует возможных строк (снова, плюс некоторая незначительная буферизация, которую мы игнорируем). Единственным преимуществом эффективности единственного подхода инструмента, который не использует каналы, является меньше процессов (и таким образом меньше служебное).
Я делаю этого достаточно часто и так написал этот скрипт. Мне не нужно найти номера строк, скрипт делает все это.
#!/bin/bash
# $1: start time
# $2: end time
# $3: log file to read
# $4: output file
# i.e. log_slice.sh 18:33 19:40 /var/log/my.log /var/log/myslice.log
if [[ $# != 4 ]] ; then
echo 'usage: log_slice.sh <start time> <end time> <log file> <output file>'
echo
exit;
fi
if [ ! -f $3 ] ; then
echo "'$3' doesn't seem to exit."
echo 'exiting.'
exit;
fi
sline=$(grep -n " ${1}" $3|head -1|cut -d: -f1) #what line number is first occurrance of start time
eline=$(grep -n " ${2}" $3|head -1|cut -d: -f1) #what line number is first occurrance of end time
linediff="$((eline-sline))"
tail -n+${sline} $3|head -n$linediff > $4
Если мы знаем диапазон для выбора, от первой строки: lStart
до последней строки: lEnd
, мы можем вычислить:
lCount="$((lEnd-lStart+1))"
Если мы знаем общее количество строк : lAll
, мы также можем вычислить расстояние до конца файла:
toEnd="$((lAll-lStart+1))"
Тогда мы узнаем и то, и другое:
"how far from the start" ($lStart) and
"how far from the end of the file" ($toEnd).
Выбираем наименьшее из них: tailnumber
как это :
tailnumber="$toEnd"; (( toEnd > lStart )) && tailnumber="+$linestart"
Позволяет нам использовать наиболее быстро выполняющуюся команду:
tail -n"${tailnumber}" ${thefile} | head -n${lCount}
Обратите внимание на дополнительный знак плюса («+»), когда выбран $ linestart
.
Единственное предостережение: нам нужно общее количество строк, и это может занять некоторое время, чтобы найти.
Как обычно с:
linesall="$(wc -l < "$thefile" )"
lStart |500| lEnd |500| lCount |11|
real user sys frac
0.002 0.000 0.000 0.00 | command == tail -n"+500" test.in | head -n1
0.002 0.000 0.000 0.00 | command == tail -n+500 test.in | head -n1
3.230 2.520 0.700 99.68 | command == tail -n99999501 test.in | head -n1
0.001 0.000 0.000 0.00 | command == head -n500 test.in | tail -n1
0.001 0.000 0.000 0.00 | command == sed -n -e "500,500p;500q" test.in
0.002 0.000 0.000 0.00 | command == awk 'NR<'500'{next}1;NR=='500'{exit}' test.in
lStart |50000000| lEnd |50000010| lCount |11|
real user sys frac
0.977 0.644 0.328 99.50 | command == tail -n"+50000000" test.in | head -n11
1.069 0.756 0.308 99.58 | command == tail -n+50000000 test.in | head -n11
1.823 1.512 0.308 99.85 | command == tail -n50000001 test.in | head -n11
1.950 2.396 1.284 188.77| command == head -n50000010 test.in | tail -n11
5.477 5.116 0.348 99.76 | command == sed -n -e "50000000,50000010p;50000010q" test.in
10.124 9.669 0.448 99.92| command == awk 'NR<'50000000'{next}1;NR=='50000010'{exit}' test.in
lStart |99999000| lEnd |99999010| lCount |11|
real user sys frac
0.001 0.000 0.000 0.00 | command == tail -n"1001" test.in | head -n11
1.960 1.292 0.660 99.61 | command == tail -n+99999000 test.in | head -n11
0.001 0.000 0.000 0.00 | command == tail -n1001 test.in | head -n11
4.043 4.704 2.704 183.25| command == head -n99999010 test.in | tail -n11
10.346 9.641 0.692 99.88| command == sed -n -e "99999000,99999010p;99999010q" test.in
21.653 20.873 0.744 99.83 | command == awk 'NR<'99999000'{next}1;NR=='99999010'{exit}' test.in
Обратите внимание, что время резко меняется, если выбранные строки находятся около начала или ближе к концу. Команда, которая хорошо работает на одной стороне файла, может быть очень медленной на другой стороне файла.
Если вы cat данные, вы захотите использовать сначала хвост, а затем голову.
cat file.name | tail -n +"3" | head -n -"1"
tail -n +50000000 test.in | head -n10
, который, в отличие от этого,tail -n-50000000 test.in | head -n10
дал бы корректный результат? – Gilles 'SO- stop being evil' 08.09.2012, 13:55tail+|head
быстрее 10-15%, чем sed, я добавил тот сравнительный тест. – Kevin 08.09.2012, 16:50-c
пропускать символы,tail+|head
мгновенно. Конечно, Вы не можете сказать "50000000" и, вероятно, придется вручную найти запуск раздела, который Вы ищете. – Danny Kirchmeier 25.04.2014, 19:26