Самую длинную строчку можно найти таким конвеером:
cat file |while read -r s; do echo $(echo $s| wc -c) $s; done |sort -grk1 | head -n1
Да и самую короткую можно аналогично (на мой взгляд, куда проще, чем Ваш «простой» sed-скрипт). Но это не полное решение: самых длинных (коротких) строк может быть несколько.
Да и самую короткую можно аналогично (на мой взгляд, куда проще, чем Ваш «простой» sed-скрипт). Но это не полное решение: самых длинных (коротких) строк может быть несколько.
Ну, мой sed-скрипт если не проще, то, во всяком случае, короче варианта на awk, предложенного KiWi (:
Полное решение, с поиском всех самых коротких строк, может выглядеть так:
awk-скрипт всё же более нагляден по сравнению с sed'ом.) sed тоже хорош для своих задач, просто порой не такой наглядный, как awk. Последний лаконичен. ^_^
ИМХО самые длинные/короткие строки проще всего можно найти простой заменой всех символов на какой-нибудь неиспользуемый символ, что-то вроде
sed 's/./~/g'
после чего, получившиеся строки надо отсортировать, тогда самые короткие(длинные) строки будут в начале(конце) списка:
Стесняюсь спросить, приведённая команда выполнить аналогичное действие?
на всех комбинациях входных данных, которые я смог вообразить, эти две команды действуют идентично:
sed -nr 's/^address\s(.*)$/\1/p' $FILE
sed -n 's/^address\s//p' $FILE
а вот приведённый вариант на awk действует совершенно иначе. например, он выдаст «123», если в файле содержится, например,
Это понятно, условие стоит менее строгое, но данный пример приводился как "более" понятный синтаксис, чем у sed.
А Вы напишите для awk полный вариант и сравните не с Вашим бесполезно перегруженным для sed, а с вариантом от sash-kan (как Александр уже сказал, по результату они эквивалентны) — тогда и посмотрим, что проще.
drBatty,
спасибо, способ довольно интересный, только не понятно, зачем такие длинные последовательности пробелов?
и /~+/ оказывается в конце строчек, а не в начале?
Попробовал посравнивать разные варианты на предмет быстродействия, отыскивая самые длинные строки в файле /var/log/pacman.log, там уже 25 тыс. строк.
Самым быстрым оказался awk (GNU Awk 3.1.8), принимаем его время за единицу.
Далее вариант drBatty (GNU sed версии 4.2.1), его время 14.
На третьем месте „чистый bash“ (GNU bash, version 4.1.7), его время 28. Не так уж и медлительно, можно сказать.
Мой простенький sed-скрипт отстает от awk в 371 раз.
А вот конвейер, типа приведенного в сообщении #3, работает действительно медленно. Его время 1439.
А вот конвейер, типа приведенного в сообщении #3, работает действительно медленно. Его время 1439.
А кто-то говорил, что он будет работать быстро?)
Передача данных между приложениями(запись в одном, чтение в другом).
И памяти жрать оно будет, скорее всего, размером с ВЕСЬ файл -- чтобы файл отсортировать его нужно весь прочитать)
Тут дело не в сортировке, во втором по быстродействию варианте (вариант drBatty) тоже сортировка используется… bash без сортировки, но с ${#string}, работает в два раза медленнее.
Причина, как я понимаю, в непрерывном дёрганье wc для каждой строки.
на всех комбинациях входных данных, которые я смог вообразить, эти две команды действуют идентично:
sed -nr 's/^address\s(.*)$/\1/p' $FILE
sed -n 's/^address\s//p' $FILE
результат будет разным если есть НЕсимволы. например дырки в UTF - 0xd1d1 например - это не совпадает с точкой.
Самым быстрым оказался awk (GNU Awk 3.1.8), принимаем его время за единицу.
Далее вариант drBatty (GNU sed версии 4.2.1), его время 14.
На третьем месте „чистый bash“ (GNU bash, version 4.1.7), его время 28. Не так уж и медлительно, можно сказать.
Мой простенький sed-скрипт отстает от awk в 371 раз.
Тут дело не в сортировке, во втором по быстродействию варианте (вариант drBatty) тоже сортировка используется… bash без сортировки, но с ${#string}, работает в два раза медленнее.
Причина, как я понимаю, в непрерывном дёрганье wc для каждой строки.
Bash вообще медленный:
zyx@zyx-desktop
(zyx:~) % time ( cat /var/log/emerge.log |while read -r s; do echo ${#s} $s; done |sort -grk1 | head -n1 ) > /dev/null
(; cat /var/log/emerge.log | while read -r s; do; echo ${#s} $s; done | sort 0,00s user 0,00s system 0% cpu 4,297 total
(zyx:~) % time bash -c 'cat /var/log/emerge.log |while read -r s; do echo ${#s} $s; done |sort -grk1 | head -n1' > /dev/null
bash -c > /dev/null 11,40s user 2,17s system 102% cpu 13,252 total
(zyx:~) % echo $ZSH_VERSION
4.3.10
(zyx:~) % bash -c 'echo $BASH_VERSION'
4.0.37(2)-release
Остальные варианты:
zyx@zyx-desktop
(zyx:~) % time ( cat /var/log/emerge.log | awk '{ print length($0), $0; }' | sort -grk 1 | head -n1 | cut -d' ' -f'2-' ) >/dev/null
(; cat /var/log/emerge.log | awk '{ print length($0), $0; }' | sort -grk 1 | 0,00s user 0,00s system 0% cpu 1,190 total
(zyx:~) % time ( cat /var/log/emerge.log | awk 'BEGIN { LEN=-1; STR=""; }; END { print STR; }; { if (length($0) > LEN || LEN == -1) { LEN=length($0); STR=$0; } }' ) > /dev/null
(; cat /var/log/emerge.log | awk ; ) > /dev/null 0,46s user 0,01s system 99% cpu 0,471 total
(zyx:~) % time ( cat /var/log/emerge.log | sed 'h; s/./a/g; G; s/\n/ /' | sort | sed 's/^a* //' ) > /dev/null
(; cat /var/log/emerge.log | sed 'h; s/./a/g; G; s/\n/ /' | sort | sed ; ) > 0,17s user 0,02s system 2% cpu 8,375 total
Кстати, если переписать самый быстрый вариант с awk на perl, то получится намного быстрее:
zyx@zyx-desktop
(zyx:~) % time ( perl -p -e 'BEGIN { @L=(-1) } END { print $L[-1] } @L=((length), $_) if((length)>$L[0]); undef $_;' /var/log/emerge.log ) > /dev/null
(; perl -p -e /var/log/emerge.log; ) > /dev/null 0,08s user 0,01s system 99% cpu 0,086 total
#!/bin/bash
MAX=0
STR=""
while read -r s; do
CUR=${#s}
if test $CUR -gt $MAX; then
MAX=$CUR
STR="$s"
elif test $CUR -eq $MAX; then
STR=$(echo -e "$STR""\n$s")
else
continue
fi
done
echo "$STR"
Соответственно, и в конец конвейера чуть-чуть дописал (это не сильно влияет на производительность при небольшом числе самых длинных строк):
#!/bin/sh
while read s; do
echo "$(echo $s| wc -c)" "$s";
done |sort -grk1 | while read -r s; do
CUR=$(echo "$s"|wc -c)
if test -z $TOP; then
TOP=$CUR
fi
if test $TOP -eq $CUR; then
echo "$s" | cut -d' ' -f2-
else
break
fi
done