Комментарии 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
мне одному кажет, что они всё же по разному работают при разделителе «пробел»?
+3
ls -la |cut -f 4 -d ' '
0
Именно что по разному.
Если 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
0
по умолчанию, похоже, только TAB разделитель для cut
«use DELIM instead of TAB for field delimiter» (с) man cut
«use DELIM instead of TAB for field delimiter» (с) man cut
0
> В современном линуксе обработка вызова awk куда более сложна, чем вызов cut.
Настолько большие издержки?
Настолько большие издержки?
0
доходит до смешного:
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
с грепом на регекспах даже не стал проверять, регекспы весьма тормозная штука сама по себе.
считаю, что проблема высосана автором из пальца
+8
это у вас /var/log/messages удлинился к моменту cut'а =)
на самом деле не вижу в awk ничего предосудительного, отличный инструмент с кучей возможностей и почему автор против его использования не понимаю, пусть даже это и простые конструкции, но они же есть в нем.
на самом деле не вижу в awk ничего предосудительного, отличный инструмент с кучей возможностей и почему автор против его использования не понимаю, пусть даже это и простые конструкции, но они же есть в нем.
+3
На самом деле awk действительно медленнее. В конкретно этой операции выигрыш от использования cut — 2-3 раза, но операция даже на логах 2-3мб выполняется за сотые доли секунды и мне сложно представить ситуацию когда это было бы важно…
Если же взять какой то сложный текст то тут разница будет очень большая, в десятки раз, но в случае со сложным текстом cut в 99% случаев просто бесполезен в силу своей примитивности.
Если же взять какой то сложный текст то тут разница будет очень большая, в десятки раз, но в случае со сложным текстом cut в 99% случаев просто бесполезен в силу своей примитивности.
0
НЛО прилетело и опубликовало эту надпись здесь
Вы не то считаете. Речь не о скорости единичного вызова, а о множестве вызовов:
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
Вот об этих милисекундах речь и идёт.
-1
Это, простите, Вы не то считаете. Вы запустите обработку крупного файла, а не мелкого и увидете, что 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
0
Вместо 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
+3
блин, про strace я забыл начисто, спасибо.
количество вызовов явно говорит не в пользу cat, что и требовалось доказать.
похоже, что данный топик доказывает одно: если люди годами в шелле используют какой-то простой метод и не используют другие, так же хорошо известные — то скорее всего что-то в этом есть.
количество вызовов явно говорит не в пользу cat, что и требовалось доказать.
похоже, что данный топик доказывает одно: если люди годами в шелле используют какой-то простой метод и не используют другие, так же хорошо известные — то скорее всего что-то в этом есть.
0
А сколько лесов будет сэкономлено на планете, если все откажутся от awk?
+8
Я думаю, в контексте статьи заслуживает внимания и утилита sed. Часто её используют после grep, но на самом деле это лишнее.
$ ls -la | sed -n '/^d/p'
Выводит все поддиректории.
Это очень простой пример, возможности sed'а просто огромны.
$ ls -la | sed -n '/^d/p'
Выводит все поддиректории.
Это очень простой пример, возможности sed'а просто огромны.
+3
Если возникнет потребность экономить ресурсы в подобной задаче — то лучше все же использовать 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 на строчки с разным содержимым и потом грепать то что нужно.
0
grep | awk?
awk '/regexp/{script}'
awk '/regexp/{script}'
+1
Если нужно экономить ресурсы, то лучше не использовать перл. swtch.com/~rsc/regexp/regexp1.html
0
я прекрасно понимаю, что перл не самый быстрый движок регулярных выражений, но если для того чтобы вытащить нужную мне инфу из логов мне надо будет ставить какие-то нестандартные либы, писать что-то на C, и возится еще неизвестно с чем…
Я лучше смирюсь с неоптимальностью перла и напишу за 5 минут однострочник
Тем более, что потратил когда-то несколько дней на «Mastering Regular Expressions» и могу написать регулярку, которая работает с приемлемой скоростью
Я лучше смирюсь с неоптимальностью перла и напишу за 5 минут однострочник
Тем более, что потратил когда-то несколько дней на «Mastering Regular Expressions» и могу написать регулярку, которая работает с приемлемой скоростью
0
Думаю, у автора не было достаточного опыта в обработке «разношёрстных» данных средствами *nix утилит. Иначе не было бы и таких категоричных заявлений.
PS. Попробуйте cut'ом выдернуть из squid'ового access.log, например, урл. Для awk это 7-ое поле, а что вернёт cut?
PS. Попробуйте cut'ом выдернуть из squid'ового access.log, например, урл. Для awk это 7-ое поле, а что вернёт cut?
+4
Часто вижу как используют.
cat file.txt | grep tt
Ну ведь можно же не использовать cat?
cat file.txt | grep tt
Ну ведь можно же не использовать cat?
0
можно не использовать но где гарантия что grep «сможет» на «всём» так как вы от него ожидаете, гарантии нет, поэтому я бы написал именно так
cat file.txt | grep tt
а не
grep tt file.txt
cat file.txt | grep tt
а не
grep tt file.txt
0
grep tt < file.txt
0
Насколько я помню, этот вариант с перенаправлением файла на 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.
-1
кто то по ссылке выше врёт… возможно они не учли кэширование…
$ 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
0
Вот вот, я об этом и говорю :) Просто не стал расписывать, тут люди грамотные!
0
я вот чего скажу… мне пришлось переписывать скрипты для работы fish в mc, столкнулся с тем что базовые утилиты ls, head, tail, cut работают (имеют разные ключи) чуть по разному в зависимости от реализации т.е. даже в разных версиях бизибокса они бывает различаются, не говоря о разных реализациях никсов. так что при выборе cut или awk я бы не был столь категоричен.
0
foobar | (read p1 p2; echo p1)
команда 'read' встроена в оболочку (в bash, по крайней мере), потому ресурсоёмкость будет ещё ниже, чем с 'cut'
команда 'read' встроена в оболочку (в bash, по крайней мере), потому ресурсоёмкость будет ещё ниже, чем с 'cut'
+2
А вот это, кстати, интересно. Спасибо.
0
только вот скобочки () запустят новый экземпляр шелла — а юмор в том, что запускать огромный и тяжеловесный шелл — такой, как bash — тяжелее и хуже, чем маленький и шустрый cut
0
не правда, не запустят
сравните вывод таких комманд:
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
+2
Спасибо за комментарий :) Приятно говорить с человеком, который в теме и оперирует адекватными аргументами ;)
Тем не менее, шеллу не обязательно делать 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.
0
Ну смотря что понимать под запуском. Copy on write давным давно применяется в ядре. Сам спавнинг процесса будет занимать примерно одно и то же время. А инициализация я думаю там в любом случае к минимуму сведена. Как раз из соображений пакетного запуска.
Но это если придираться :) А так в общем то специализированные микротулзы лучше
Но это если придираться :) А так в общем то специализированные микротулзы лучше
0
Пардон, не видел вашего комментария выше. Действительно разница довольно ощутима
0
cut? grep? awk? или как использовать cut в высоконагрузочных проектах. Такое название должно было блистать.
-1
Только у меня на всех ОСях (Арчи, Бунта, Деби, БСД) cut не знает о ключе -f?
$ cut -f
cut: ключ должен использоваться с аргументом — «f»
Попробуйте `cut --help' для получения более подробного описания.
$ cut -f
cut: ключ должен использоваться с аргументом — «f»
Попробуйте `cut --help' для получения более подробного описания.
-1
«зубило и молоток или дремель ?» =)
0
НЛО прилетело и опубликовало эту надпись здесь
"{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))»
0
Зарегистрируйтесь на Хабре , чтобы оставить комментарий
cut и grep или awk?