Comments 58
agup@web ~ $ ls -la |cut -f 4
total 8
drwxr-xr-x 4 agup agup 160 2010-09-20 08:03.
drwxr-xr-x 5 link01n wheel 344 2010-09-15 00:42…
-rw------- 1 agup agup 1524 2010-09-20 02:49 .bash_history
-rw------- 1 agup ssmtp 933 2010-09-20 02:10 dead.letter
drwx------ 3 agup agup 200 2010-09-20 02:49 .mc
drwxr-xr-x 2 agup agup 80 2010-09-15 00:45 .ssh
agup@web ~ $ ls -la |awk '{print $4}'
agup
wheel
agup
ssmtp
agup
agup
мне одному кажет, что они всё же по разному работают при разделителе «пробел»?
total 8
drwxr-xr-x 4 agup agup 160 2010-09-20 08:03.
drwxr-xr-x 5 link01n wheel 344 2010-09-15 00:42…
-rw------- 1 agup agup 1524 2010-09-20 02:49 .bash_history
-rw------- 1 agup ssmtp 933 2010-09-20 02:10 dead.letter
drwx------ 3 agup agup 200 2010-09-20 02:49 .mc
drwxr-xr-x 2 agup agup 80 2010-09-15 00:45 .ssh
agup@web ~ $ ls -la |awk '{print $4}'
agup
wheel
agup
ssmtp
agup
agup
мне одному кажет, что они всё же по разному работают при разделителе «пробел»?
ls -la |cut -f 4 -d ' '
Именно что по разному.
Если cut встречает три пробела подряд то думает что это три колонки.
Если cut встречает три пробела подряд то думает что это три колонки.
void@void-desktop:~$ cat /proc/diskstats | grep 'sda1' | awk '{ print $11 }' 11616912 void@void-desktop:~$ cat /proc/diskstats | grep 'sda1' | cut -d " " -f 11 1 void@void-desktop:~$ cat /proc/diskstats | grep 'sda1' 8 1 sda1 63909 32026 3654959 1353464 515988 6240056 54055512 11617108 0 2153816 12972816
по умолчанию, похоже, только TAB разделитель для cut
«use DELIM instead of TAB for field delimiter» (с) man cut
«use DELIM instead of TAB for field delimiter» (с) man cut
> В современном линуксе обработка вызова awk куда более сложна, чем вызов cut.
Настолько большие издержки?
Настолько большие издержки?
доходит до смешного:
time awk -F: '{print $1}' /var/log/messages
real 0m0.186s
user 0m0.032s
sys 0m0.024s
time cut -f 1 -d: -s /var/log/messages
real 0m0.237s
user 0m0.151s
sys 0m0.027s
с грепом на регекспах даже не стал проверять, регекспы весьма тормозная штука сама по себе.
считаю, что проблема высосана автором из пальца
time awk -F: '{print $1}' /var/log/messages
real 0m0.186s
user 0m0.032s
sys 0m0.024s
time cut -f 1 -d: -s /var/log/messages
real 0m0.237s
user 0m0.151s
sys 0m0.027s
с грепом на регекспах даже не стал проверять, регекспы весьма тормозная штука сама по себе.
считаю, что проблема высосана автором из пальца
это у вас /var/log/messages удлинился к моменту cut'а =)
на самом деле не вижу в awk ничего предосудительного, отличный инструмент с кучей возможностей и почему автор против его использования не понимаю, пусть даже это и простые конструкции, но они же есть в нем.
на самом деле не вижу в awk ничего предосудительного, отличный инструмент с кучей возможностей и почему автор против его использования не понимаю, пусть даже это и простые конструкции, но они же есть в нем.
На самом деле awk действительно медленнее. В конкретно этой операции выигрыш от использования cut — 2-3 раза, но операция даже на логах 2-3мб выполняется за сотые доли секунды и мне сложно представить ситуацию когда это было бы важно…
Если же взять какой то сложный текст то тут разница будет очень большая, в десятки раз, но в случае со сложным текстом cut в 99% случаев просто бесполезен в силу своей примитивности.
Если же взять какой то сложный текст то тут разница будет очень большая, в десятки раз, но в случае со сложным текстом cut в 99% случаев просто бесполезен в силу своей примитивности.
UFO just landed and posted this here
Вы не то считаете. Речь не о скорости единичного вызова, а о множестве вызовов:
time for a in `seq 1 1000`; do echo /etc/inittab|awk '{print $1}'>/dev/null;done
real 0m1.942s
user 0m0.620s
sys 0m1.760s
time for a in `seq 1 1000`; do echo /etc/inittab|cut -f 1 -s — >/dev/null;done
real 0m1.495s
user 0m0.368s
sys 0m1.516s
Вот об этих милисекундах речь и идёт.
time for a in `seq 1 1000`; do echo /etc/inittab|awk '{print $1}'>/dev/null;done
real 0m1.942s
user 0m0.620s
sys 0m1.760s
time for a in `seq 1 1000`; do echo /etc/inittab|cut -f 1 -s — >/dev/null;done
real 0m1.495s
user 0m0.368s
sys 0m1.516s
Вот об этих милисекундах речь и идёт.
Это, простите, Вы не то считаете. Вы запустите обработку крупного файла, а не мелкого и увидете, что cat крайне не эффективен собственно в обработке. Кажущаяся выгода за счет размера cat'а нивелируется тем, что сам обработчик awk значительно эффективнее.
igor@gonzo:~$ time for a in `seq 1 1000`; do cut -f 1 -d: -s /var/log/messages > /dev/none; done
real 1m20.908s
user 1m14.933s
sys 0m2.538s
igor@gonzo:~$ time for a in `seq 1 1000`; do awk -F: '{print $1}' /var/log/messages > /dev/null; done
real 0m9.973s
user 0m6.062s
sys 0m2.663s
igor@gonzo:~$ time for a in `seq 1 1000`; do cut -f 1 -d: -s /var/log/messages > /dev/none; done
real 1m20.908s
user 1m14.933s
sys 0m2.538s
igor@gonzo:~$ time for a in `seq 1 1000`; do awk -F: '{print $1}' /var/log/messages > /dev/null; done
real 0m9.973s
user 0m6.062s
sys 0m2.663s
Вместо time лучше сделать strace -c ИМХО нагляднее
# strace -c awk '{print $1}' /var/log/asterisk/full.3 > /dev/null % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 98.92 0.003481 0 14284 read 1.08 0.000038 0 649 write 0.00 0.000000 0 7 open 0.00 0.000000 0 7 close 0.00 0.000000 0 1 execve 0.00 0.000000 0 1 1 access 0.00 0.000000 0 3 brk 0.00 0.000000 0 3 3 ioctl 0.00 0.000000 0 1 munmap 0.00 0.000000 0 4 mprotect 0.00 0.000000 0 3 rt_sigaction 0.00 0.000000 0 13 mmap2 0.00 0.000000 0 12 fstat64 0.00 0.000000 0 2 getgroups32 0.00 0.000000 0 1 fcntl64 0.00 0.000000 0 1 set_thread_area ------ ----------- ----------- --------- --------- ---------------- 100.00 0.003519 14992 4 total # strace -c cut -f 1 /var/log/asterisk/full.3 > /dev/null % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 62.96 0.004210 1 7143 read 36.59 0.002447 0 14280 write 0.45 0.000030 3 10 mmap2 0.00 0.000000 0 5 open 0.00 0.000000 0 6 close 0.00 0.000000 0 1 execve 0.00 0.000000 0 1 1 access 0.00 0.000000 0 3 brk 0.00 0.000000 0 1 1 ioctl 0.00 0.000000 0 3 munmap 0.00 0.000000 0 2 mprotect 0.00 0.000000 0 6 fstat64 0.00 0.000000 0 1 set_thread_area ------ ----------- ----------- --------- --------- ---------------- 100.00 0.006687 21462 2 total
блин, про strace я забыл начисто, спасибо.
количество вызовов явно говорит не в пользу cat, что и требовалось доказать.
похоже, что данный топик доказывает одно: если люди годами в шелле используют какой-то простой метод и не используют другие, так же хорошо известные — то скорее всего что-то в этом есть.
количество вызовов явно говорит не в пользу cat, что и требовалось доказать.
похоже, что данный топик доказывает одно: если люди годами в шелле используют какой-то простой метод и не используют другие, так же хорошо известные — то скорее всего что-то в этом есть.
А сколько лесов будет сэкономлено на планете, если все откажутся от awk?
Я думаю, в контексте статьи заслуживает внимания и утилита sed. Часто её используют после grep, но на самом деле это лишнее.
$ ls -la | sed -n '/^d/p'
Выводит все поддиректории.
Это очень простой пример, возможности sed'а просто огромны.
$ ls -la | sed -n '/^d/p'
Выводит все поддиректории.
Это очень простой пример, возможности sed'а просто огромны.
Если возникнет потребность экономить ресурсы в подобной задаче — то лучше все же использовать AWK или perl, на нем можно описать более умный алгоритм, который даст реальную экономию :)
вот пример:
mailq | tail -n +2 | grep -v '^ *(' | awk 'BEGIN { RS = "" } { if ($8 == «user@example.com») print $1 } ' | tr -d '*!'
думаю согласитесь, что это намного эффективнее, чем делать cut на строчки с разным содержимым и потом грепать то что нужно.
вот пример:
mailq | tail -n +2 | grep -v '^ *(' | awk 'BEGIN { RS = "" } { if ($8 == «user@example.com») print $1 } ' | tr -d '*!'
думаю согласитесь, что это намного эффективнее, чем делать cut на строчки с разным содержимым и потом грепать то что нужно.
grep | awk?
awk '/regexp/{script}'
awk '/regexp/{script}'
Если нужно экономить ресурсы, то лучше не использовать перл. swtch.com/~rsc/regexp/regexp1.html
я прекрасно понимаю, что перл не самый быстрый движок регулярных выражений, но если для того чтобы вытащить нужную мне инфу из логов мне надо будет ставить какие-то нестандартные либы, писать что-то на C, и возится еще неизвестно с чем…
Я лучше смирюсь с неоптимальностью перла и напишу за 5 минут однострочник
Тем более, что потратил когда-то несколько дней на «Mastering Regular Expressions» и могу написать регулярку, которая работает с приемлемой скоростью
Я лучше смирюсь с неоптимальностью перла и напишу за 5 минут однострочник
Тем более, что потратил когда-то несколько дней на «Mastering Regular Expressions» и могу написать регулярку, которая работает с приемлемой скоростью
Думаю, у автора не было достаточного опыта в обработке «разношёрстных» данных средствами *nix утилит. Иначе не было бы и таких категоричных заявлений.
PS. Попробуйте cut'ом выдернуть из squid'ового access.log, например, урл. Для awk это 7-ое поле, а что вернёт cut?
PS. Попробуйте cut'ом выдернуть из squid'ового access.log, например, урл. Для awk это 7-ое поле, а что вернёт cut?
Часто вижу как используют.
cat file.txt | grep tt
Ну ведь можно же не использовать cat?
cat file.txt | grep tt
Ну ведь можно же не использовать cat?
можно не использовать но где гарантия что grep «сможет» на «всём» так как вы от него ожидаете, гарантии нет, поэтому я бы написал именно так
cat file.txt | grep tt
а не
grep tt file.txt
cat file.txt | grep tt
а не
grep tt file.txt
grep tt < file.txt
Насколько я помню, этот вариант с перенаправлением файла на grep хуже, если работаешь с текстовыми файлами из разных операционных систем (с разными байтами перевода строк).
Например, в MS-DOS и Windows в текстовых файлах для перевода строк (newline) используются два байта: CR (0x0D, Carriage return) и LF (0x0A, Line feed). У *nix-like систем (Linux, BSD, MacOSX) — только один байт LF (0x0A). А в старой линейке MacOS (до 9 версии включительно) в качестве разделителей строк использовался один байт CR (0x0D).
Так вот при перенаправлении исходного файла это может быть обработано некорректно. А предварительный cat файла, вывод которого подаётся на grep, сначала читает текст и причёсывает файл, независимо от использованных там символов newline.
Например, в MS-DOS и Windows в текстовых файлах для перевода строк (newline) используются два байта: CR (0x0D, Carriage return) и LF (0x0A, Line feed). У *nix-like систем (Linux, BSD, MacOSX) — только один байт LF (0x0A). А в старой линейке MacOS (до 9 версии включительно) в качестве разделителей строк использовался один байт CR (0x0D).
Так вот при перенаправлении исходного файла это может быть обработано некорректно. А предварительный cat файла, вывод которого подаётся на grep, сначала читает текст и причёсывает файл, независимо от использованных там символов newline.
кто то по ссылке выше врёт… возможно они не учли кэширование…
$ time cat TAGS |grep _FILE_OFFSET_BITS #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS786,23163 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS521,14125 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS783,23107 real 0m0.440s user 0m0.430s sys 0m0.010s $ time cat TAGS |grep _FILE_OFFSET_BITS #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS786,23163 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS521,14125 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS783,23107 real 0m0.450s user 0m0.440s sys 0m0.000s $ time grep _FILE_OFFSET_BITS ./TAGS #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS786,23163 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS521,14125 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS783,23107 real 0m0.420s user 0m0.410s sys 0m0.010s $ time grep _FILE_OFFSET_BITS ./TAGS #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS786,23163 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS521,14125 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS783,23107 real 0m0.410s user 0m0.390s sys 0m0.020s $ time grep _FILE_OFFSET_BITS ./TAGS #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS786,23163 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS521,14125 #define _FILE_OFFSET_BITS_FILE_OFFSET_BITS783,23107 real 0m0.440s user 0m0.440s sys 0m0.000s
Вот вот, я об этом и говорю :) Просто не стал расписывать, тут люди грамотные!
я вот чего скажу… мне пришлось переписывать скрипты для работы fish в mc, столкнулся с тем что базовые утилиты ls, head, tail, cut работают (имеют разные ключи) чуть по разному в зависимости от реализации т.е. даже в разных версиях бизибокса они бывает различаются, не говоря о разных реализациях никсов. так что при выборе cut или awk я бы не был столь категоричен.
foobar | (read p1 p2; echo p1)
команда 'read' встроена в оболочку (в bash, по крайней мере), потому ресурсоёмкость будет ещё ниже, чем с 'cut'
команда 'read' встроена в оболочку (в bash, по крайней мере), потому ресурсоёмкость будет ещё ниже, чем с 'cut'
А вот это, кстати, интересно. Спасибо.
только вот скобочки () запустят новый экземпляр шелла — а юмор в том, что запускать огромный и тяжеловесный шелл — такой, как bash — тяжелее и хуже, чем маленький и шустрый cut
не правда, не запустят
сравните вывод таких комманд:
strace -ffe fork,vfork,execve,clone bash -c 'id | cut -f 2 -d " "'
strace -ffe fork,vfork,execve,clone bash -c 'id | (read a b c;echo $b)'
в первом случае будет два вызова execve (для запуска id и cut), во втором только один, для запуска id
сравните вывод таких комманд:
strace -ffe fork,vfork,execve,clone bash -c 'id | cut -f 2 -d " "'
strace -ffe fork,vfork,execve,clone bash -c 'id | (read a b c;echo $b)'
в первом случае будет два вызова execve (для запуска id и cut), во втором только один, для запуска id
Спасибо за комментарий :) Приятно говорить с человеком, который в теме и оперирует адекватными аргументами ;)
Тем не менее, шеллу не обязательно делать fork для запуска сабшелла — но накладные расходы на его создание всё равно порядочные; сравните:
Разница почти в 2 раза в пользу cut.
Тем не менее, шеллу не обязательно делать fork для запуска сабшелла — но накладные расходы на его создание всё равно порядочные; сравните:
$ time sh -c 'I=0; while [ $I -lt 10000 ]; do id | (read a b c; echo $b) >/dev/null; I=$(($I+1)); done' sh -c 33,91s user 37,52s system 105% cpu 1:07,58 total $ time sh -c 'I=0; while [ $I -lt 10000 ]; do id | cut -f2 -d\ >/dev/null; I=$(($I+1)); done' sh -c 28,11s user 25,85s system 149% cpu 35,977 total
Разница почти в 2 раза в пользу cut.
Ну смотря что понимать под запуском. Copy on write давным давно применяется в ядре. Сам спавнинг процесса будет занимать примерно одно и то же время. А инициализация я думаю там в любом случае к минимуму сведена. Как раз из соображений пакетного запуска.
Но это если придираться :) А так в общем то специализированные микротулзы лучше
Но это если придираться :) А так в общем то специализированные микротулзы лучше
Пардон, не видел вашего комментария выше. Действительно разница довольно ощутима
cut? grep? awk? или как использовать cut в высоконагрузочных проектах. Такое название должно было блистать.
Только у меня на всех ОСях (Арчи, Бунта, Деби, БСД) cut не знает о ключе -f?
$ cut -f
cut: ключ должен использоваться с аргументом — «f»
Попробуйте `cut --help' для получения более подробного описания.
$ cut -f
cut: ключ должен использоваться с аргументом — «f»
Попробуйте `cut --help' для получения более подробного описания.
«зубило и молоток или дремель ?» =)
UFO just landed and posted this here
"{1..100}" — это башизм, в стандартном sh его нет.
А «i=i++» — это вообще какая-то ернуда — во-первых, в цикле «seq | while» она вам абсолютно не нужно, во-вторых, «i=i++» присваивает переменной «i» строчку «i++», а совсем никак не делает тот инкремент, который подразумевался. Правильный способ делать инкремент — «i=$(($i + 1))»
А «i=i++» — это вообще какая-то ернуда — во-первых, в цикле «seq | while» она вам абсолютно не нужно, во-вторых, «i=i++» присваивает переменной «i» строчку «i++», а совсем никак не делает тот инкремент, который подразумевался. Правильный способ делать инкремент — «i=$(($i + 1))»
Sign up to leave a comment.
cut и grep или awk?