Бесполезное использование кошки?

Это, вероятно, во многих часто задаваемых вопросах - вместо использования:

cat file | command

(что называется бесполезным использованием кошки), правильный путь должен быть:

command < file

Во-вторых, "правильный" способ - ОС не должна порождать дополнительный процесс.
Несмотря на это, я продолжал использовать бесполезную кошку по двум причинам.

  1. более эстетично - мне нравится, когда данные перемещаются равномерно только слева направо. И его легче заменить cat с чем-то еще (gzcat, echo,...), добавить второй файл или вставить новый фильтр (pv, mbuffer, grep...).

  2. Я "почувствовал", что в некоторых случаях это может быть быстрее. Быстрее, потому что есть 2 процесса, 1-й (cat) читает и второй делает что угодно. И они могут работать параллельно, что иногда означает более быстрое выполнение.

Правильна ли моя логика (по 2-й причине)?

8 ответов

Решение

Я не знал о награде до сегодняшнего дня, когда какой-то новобранец пытался прикрепить UUOC на меня для одного из моих ответов. Это был cat file.txt | grep foo | cut ... | cut ..., Я дал ему часть своего разума, и только после этого посетил ссылку, которую он дал мне, ссылаясь на происхождение награды и практику этого. Дальнейшие поиски привели меня к этому вопросу. К сожалению, несмотря на сознательное рассмотрение, ни один из ответов не содержал моего обоснования.

Я не хотел защищаться, отвечая ему. В конце концов, в молодости я написал бы команду как grep foo file.txt | cut ... | cut ... потому что всякий раз, когда вы делаете частый сингл grep Если вы изучите расположение аргумента файла, и вы уже знаете, что первым является шаблон, а последующими - имена файлов.

Это был осознанный выбор, чтобы использовать cat когда я ответил на вопрос, отчасти из-за причины "хорошего вкуса" (по словам Линуса Торвальдса), но главным образом из-за неопровержимой причины функционирования.

Последняя причина более важна, поэтому я изложу ее в первую очередь. Когда я предлагаю трубопровод в качестве решения, я ожидаю, что его можно будет использовать повторно. Вполне вероятно, что конвейер будет добавлен в конце или объединен в другой конвейер. В этом случае наличие аргумента file для grep приводит к невозможности повторного использования, и вполне возможно, что это происходит без сообщения об ошибке, если аргумент file существует. И. е. grep foo xyz | grep bar xyz | wc даст вам, сколько строк в xyz содержать bar в то время как вы ожидаете количество строк, которые содержат оба foo а также bar, Необходимость изменить аргументы команды в конвейере перед ее использованием подвержена ошибкам. Добавьте к этому возможность молчаливых неудач, и это станет особенно коварной практикой.

Не менее важна и первая причина, так как много " хорошего вкуса " просто является интуитивным подсознательным обоснованием таких вещей, как молчаливые неудачи, описанные выше, о которых вы не можете вспомнить прямо в тот момент, когда какой-то человек, нуждающийся в образовании, говорит "но это не так". этот кот бесполезен ".

Тем не менее, я постараюсь также осознать ранее упомянутую причину "хорошего вкуса" Эта причина связана с ортогональным духом дизайна Unix. grep не cut а также ls не grep, Поэтому, по крайней мере, grep foo file1 file2 file3 идет вразрез с духом дизайна. Ортогональный способ сделать это cat file1 file2 file3 | grep foo, Сейчас, grep foo file1 это просто особый случай grep foo file1 file2 file3 и если вы не относитесь к нему одинаково, вы, по крайней мере, используете мозговые циклы, пытаясь избежать награды за бесполезную кошку.

Это приводит нас к аргументу, что grep foo file1 file2 file3 объединяется, и cat объединяет, так что это уместно cat file1 file2 file3 но потому что cat не объединяется в cat file1 | grep foo поэтому мы нарушаем дух обоих cat и всемогущий Unix. Что ж, если бы это было так, тогда Unix потребовалась бы другая команда, чтобы прочитать вывод одного файла и выложить его на стандартный вывод (не разбивать его на страницы или что-то еще, просто наплевать на стандартный вывод). Таким образом, вы бы имели ситуацию, когда вы говорите, cat file1 file2 или вы говорите dog file1 и добросовестно помните, чтобы избежать cat file1 чтобы избежать получения награды, а также избегая dog file1 file2 так как, надеюсь, дизайн dog выдает ошибку, если указано несколько файлов.

Надеюсь, что в этот момент вы сочувствуете дизайнерам Unix, которые не включают отдельную команду для разбивки файла на стандартный вывод, а также именуют cat для конкатенации, а не дать ему другое имя. <edit> удалены неправильные комментарии <, по факту < является эффективным средством без копирования, чтобы выложить файл в стандартный вывод, который вы можете расположить в начале конвейера, так что разработчики Unix включили что-то специально для этого </edit>

Следующий вопрос: почему важно иметь команды, которые просто выплевывают файл или объединяют несколько файлов в стандартный вывод без какой-либо дальнейшей обработки? Одна из причин - избегать использования каждой отдельной команды Unix, работающей со стандартным вводом, чтобы знать, как анализировать хотя бы один аргумент файла командной строки и использовать его в качестве ввода, если он существует. Вторая причина состоит в том, чтобы пользователи не помнили: (а) куда идут аргументы имени файла; и (b) избежать ошибки тихого конвейера, как упомянуто выше.

Это подводит нас к тому, почему grep действительно имеет дополнительную логику. Логическое обоснование состоит в том, чтобы обеспечить свободное владение пользователями для команд, которые используются часто и автономно (а не как конвейер). Это небольшой компромисс ортогональности для значительного увеличения удобства использования. Не все команды должны быть спроектированы таким образом, и команды, которые не используются часто, должны полностью избегать дополнительной логики аргументов файла (помните, что дополнительная логика приводит к ненужной хрупкости (возможность ошибки)). Исключением является разрешение файловых аргументов, как в случае grep, (кстати, обратите внимание, что ls имеет совершенно другую причину, чтобы не просто принять, но в значительной степени потребовать аргументы файла)

Наконец, что можно было бы сделать лучше, если бы такие исключительные команды, как grep (но не обязательно ls) генерировать ошибку, если стандартный ввод также доступен, когда указаны аргументы файла. Это разумно, потому что команды включают логику, которая нарушает ортогональный дух Unix для удобства пользователя. Для дальнейшего удобства пользователя, т. Е. Для предотвращения страданий, вызванных тихим отказом, такие команды не должны стесняться нарушать собственное нарушение, имея дополнительную логику, чтобы предупредить пользователя, если есть возможность тихой ошибки

Нету!

Прежде всего, не имеет значения, где в команде происходит перенаправление. Так что, если вам нравится ваше перенаправление слева от вашей команды, это нормально:

< somefile command

такой же как

command < somefile

Во-вторых, при использовании конвейера происходит n + 1 процессов и подоболочек. Это решительно медленнее. В некоторых случаях n был бы равен нулю (например, когда вы перенаправляете на встроенную оболочку), поэтому с помощью cat Вы добавляете новый процесс совершенно без необходимости.

Как обобщение: всякий раз, когда вы обнаруживаете, что используете канал, стоит потратить 30 секунд, чтобы посмотреть, сможете ли вы его устранить. (Но, вероятно, не стоит тратить на это гораздо больше времени, чем 30 секунд.) Вот несколько примеров, когда каналы и процессы часто используются без необходимости:

for word in $(cat somefile); … # for word in $(<somefile); … (or better yet, while read < somefile)

grep something | awk stuff; # awk '/something/ stuff' (similar for sed)

echo something | command; # command <<< something (although echo would be necessary for pure POSIX)

Не стесняйтесь редактировать, чтобы добавить больше примеров.

В защиту кошки:

Да,

   < input process > output 

или же

   process < input > output 

является более эффективным, но многие вызовы не имеют проблем с производительностью, поэтому вам все равно.

эргономические причины:

Мы привыкли читать слева направо, поэтому команда вроде

    cat infile | process1 | process2 > outfile

тривиально понять.

    process1 < infile | process2 > outfile

должен перепрыгнуть через process1, а затем читать слева направо. Это можно вылечить с помощью:

    < infile process1 | process2 > outfile

выглядит как-то, как будто там была стрелка, указывающая налево, где ничего нет. Более запутанным и похожим на модные цитаты является:

    process1 > outfile < infile

и генерация сценариев часто является итеративным процессом,

    cat file 
    cat file | process1
    cat file | process1 | process2 
    cat file | process1 | process2 > outfile

где вы видите свой прогресс поэтапно, в то время как

    < file 

даже не работает. Простые способы менее подвержены ошибкам, а эргономичное объединение команд с cat просто.

Другая тема заключается в том, что большинство людей подвергались воздействию> и <в качестве операторов сравнения задолго до использования компьютера и при использовании компьютера в качестве программистов, гораздо чаще подвергаются этим как таковым.

И сравнение двух операндов с <и> противоречиво, что означает

(a > b) == (b < a)

Я помню первый раз, когда использовал <для перенаправления ввода, я боялся

a.sh < file 

может означать так же, как

file > a.sh

и как-то перезаписать мой скрипт a.sh. Может быть, это проблема для многих начинающих.

редкие различия

wc -c journal.txt
15666 journal.txt
cat journal.txt | wc -c 
15666

Последний может быть использован в расчетах напрямую.

factor $(cat journal.txt | wc -c)

Конечно, <можно использовать и здесь вместо параметра файла:

< journal.txt wc -c 
15666
wc -c < journal.txt
15666

а кого это волнует - 15к?

Если бы я время от времени сталкивался с проблемами, конечно, я бы изменил свою привычку вызывать кошку.

При использовании очень большого или большого количества файлов избегать использования cat вполне подойдет. Для большинства вопросов использование кошки является ортогональным, не по теме, а не проблемой.

Начинать это бесполезное бесполезное использование кошачьих дискуссий на каждую вторую тему оболочки раздражает и скучно. Получите жизнь и ждите своей минуты славы, когда имеете дело с вопросами производительности.

Я не согласен с большинством излишне самодовольных наград UUOC, потому что, обучая кого-то другого, cat является удобным заполнителем для любой команды или сложного сложного конвейера команд, которые выдают результат, подходящий для обсуждаемой проблемы или задачи.

Это особенно верно для таких сайтов, как переполнение стека, ServerFault, Unix & Linux или любых других сайтов SE.

Если кто-то специально спрашивает об оптимизации или если вы хотите добавить дополнительную информацию о ней, тогда отлично, поговорите о том, что использование cat неэффективно. Но не ругайте людей, потому что они решили стремиться к простоте и легкости понимания в своих примерах, а не смотреть на меня, как круто я! сложность.

Короче говоря, потому что кошка не всегда кошка.

Кроме того, потому что большинство людей, которым нравится получать награды UUOC, делают это потому, что их больше интересует демонстрация того, насколько они "умны", чем помощь или обучение людей. На самом деле, они демонстрируют, что они, вероятно, просто еще один новичок, который нашел крошечную палку, чтобы побить своих сверстников.


Обновить

Вот еще один UUOC, который я разместил в ответе на /questions/25628710/kakoj-tip-sistemyi-dlya-bajtovogo-massiva-aspnet/25628720#25628720:

sqlq() {
  local filter
  filter='cat'

  # very primitive, use getopts for real option handling.
  if [ "$1" == "--delete-blank-lines" ] ; then
    filter='grep -v "^$"'
    shift
  fi

  # each arg is piped into sqlplus as a separate command
  printf "%s\n" "$@" | sqlplus -S sss/eee@sid | $filter
}

UUOC педанты сказали бы, что это UUOC, потому что это легко сделать $filter по умолчанию пустая строка и имеет if заявление сделать filter='| grep -v "^$"' но IMO, не встраивая символ трубы в $filterэта "бесполезная" cat служит чрезвычайно полезной цели самодокументирования того факта, что $filter на printf линия не просто еще один аргумент sqlplusэто необязательный выбираемый пользователем выходной фильтр.

Если есть необходимость иметь несколько дополнительных выходных фильтров, обработка параметров может просто добавить | whatever в $filter так часто, как это необходимо - один дополнительный cat в конвейере ничего не повредит и не вызовет заметной потери производительности.

С версией UUoC, cat должен прочитать файл в память, затем записать его в канал, и команда должна прочитать данные из канала, поэтому ядро ​​должно скопировать весь файл три раза, тогда как в перенаправленном случае ядро ​​должно только скопируйте файл один раз. Быстрее сделать что-то один раз, чем три раза.

С помощью:

cat "$@" | command

это совершенно другое и не обязательно бесполезное использование cat, Это все еще бесполезно, если команда является стандартным фильтром, который принимает ноль или более аргументов имени файла и обрабатывает их по очереди. Рассмотрим tr Команда: это чистый фильтр, который игнорирует или отклоняет аргументы имени файла. Чтобы подать несколько файлов к нему, вы должны использовать cat как показано. (Конечно, есть отдельное обсуждение, что дизайн tr не очень хорошо; нет никакой реальной причины, по которой он не мог бы быть разработан как стандартный фильтр.) Это также может быть допустимо, если вы хотите, чтобы команда воспринимала все входные данные как один файл, а не как несколько отдельных файлов, даже если команда будет принимать несколько отдельных файлы: например, wc такая команда.

Это cat single-file случай, который безусловно бесполезен.

Как человек, который регулярно указывает на этот и ряд других антипаттернов программирования оболочки, я чувствую себя вынужденным, с опозданием, взвесить.

Сценарий оболочки очень похож на язык копирования / вставки. Для большинства людей, которые пишут сценарии оболочки, они не хотят изучать язык; это просто препятствие, которое они должны преодолеть, чтобы продолжать делать вещи на языке (ах), с которым они фактически знакомы.

В этом контексте я считаю, что распространять различные антишаблоны сценариев оболочки разрушительно и потенциально даже разрушительно. Код, который кто-то находит в Stack Overflow, в идеале должен иметь возможность копировать / вставлять в свою среду с минимальными изменениями и неполным пониманием.

Среди множества ресурсов по созданию сценариев оболочки в сети Stack Overflow необычен тем, что пользователи могут помочь улучшить качество сайта, отредактировав вопросы и ответы на сайте. Однако редактирование кода может быть проблематичным, поскольку легко вносить изменения, которые не были предназначены автором кода. Следовательно, мы склонны оставлять комментарии, чтобы предлагать изменения в коде.

Комментарии UUCA и связанные с ними паттерны предназначены не только для авторов кода, который мы комментируем; они также являются бдительными оппонентами, чтобы помочь читателям сайта узнать о проблемах в коде, который они находят здесь.

Мы не можем надеяться на то, что не найдутся ответы на вопросы о переполнении стека. cats (или переменные без кавычек, или chmod 777или большое количество других недомоганий от паттернов), но мы, по крайней мере, можем помочь обучить пользователя, который собирается скопировать / вставить этот код в самый тесный цикл своего скрипта, который выполняется миллионы раз.

Что касается технических причин, традиционная мудрость заключается в том, что мы должны попытаться минимизировать количество внешних процессов; это продолжает оставаться хорошим общим руководством при написании сценариев оболочки.

Дополнительная проблема заключается в том, что канал может скрывать скрытую оболочку. Для этого примера я заменю cat с echo, но такая же проблема существует.

echo "foo" | while read line; do
    x=$line
done

echo "$x"

Вы можете ожидать x содержать foo, но это не так. x Вы установили, был в скорлупе, порожденной, чтобы выполнить while петля. x в оболочке, которая запустила, конвейер имеет несвязанное значение или не задан вообще.

В bash4 вы можете настроить некоторые параметры оболочки так, чтобы последняя команда конвейера выполнялась в той же оболочке, что и та, которая запускает конвейер, но тогда вы можете попробовать это

echo "foo" | while read line; do
    x=$line
done | awk '...'

а также x снова местный whileРаковина

Я часто использую cat file | myprogram в примерах. Иногда меня обвиняют в бесполезном использовании кошки ( http://porkmail.org/era/unix/award.html). Я не согласен по следующим причинам:

  • Легко понять, что происходит.

    При чтении команды UNIX вы ожидаете команду, за которой следуют аргументы и перенаправление. Перенаправление можно разместить где угодно, но это редко можно увидеть - таким образом, людям будет сложнее читать пример. я верю

    cat foo | program1 -o option -b option | program2
    

    легче читать, чем

    program1 -o option -b option < foo | program2
    

    Если вы переместите перенаправление в начало, вы вводите в заблуждение людей, которые не привыкли к этому синтаксису:

    < foo program1 -o option -b option | program2
    

    и примеры должны быть легкими для понимания.

  • Это легко изменить.

    Если вы знаете, что программа может читать с catобычно вы можете предполагать, что он может читать выходные данные любой программы, которая выводит данные в STDOUT, и, таким образом, вы можете адаптировать его для своих собственных нужд и получать предсказуемые результаты.

  • Подчеркивается, что программа не даст сбой, если STDIN не является файлом.

    Не безопасно предполагать, что если program1 < foo работает тогда cat foo | program1 тоже будет работать. Однако можно предположить обратное. Эта программа работает, если STDIN является файлом, но завершается неудачей, если вход является каналом, потому что она использует поиск:

    # works
    < foo perl -e 'seek(STDIN,1,1) || die;print <STDIN>'
    
    # fails
    cat foo | perl -e 'seek(STDIN,1,1) || die;print <STDIN>'
    

Стоимость исполнения

Существует стоимость выполнения дополнительных cat, Чтобы дать представление о том, сколько я провел несколько тестов для имитации базовой линии (cat), низкая пропускная способность (bzip2), средняя пропускная способность (gzip) и высокая пропускная способность (grep).

cat $ISO | cat
< $ISO cat
cat $ISO | bzip2
< $ISO | bzip2
cat $ISO | gzip
< $ISO gzip
cat $ISO | grep no_such_string
< $ISO grep no_such_string

Тесты проводились на младшей системе (0,6 ГГц) и обычном ноутбуке (2,2 ГГц). Они запускались 10 раз в каждой системе, и было выбрано наилучшее время для имитации оптимальной ситуации для каждого теста. $ISO был ubuntu-11.04-desktop-i386.iso. (Красивые таблицы здесь: http://oletange.blogspot.com/2013/10/useless-use-of-cat.html)

CPU                       0.6 GHz ARM
Command                   cat $ISO|                        <$ISO                            Diff                             Diff (pct)
Throughput \ Time (ms)    User       Sys        Real       User       Sys        Real       User       Sys        Real       User       Sys        Real
Baseline (cat)                     55      14453      33090         23       6937      33126         32       7516        -36        239        208         99
Low (bzip2)                   1945148      16094    1973754    1941727       5664    1959982       3420      10430      13772        100        284        100
Medium (gzip)                  413914      13383     431812     407016       5477     416760       6898       7906      15052        101        244        103
High (grep no_such_string)      80656      15133      99049      79180       4336      86885       1476      10797      12164        101        349        114

CPU                       Core i7 2.2 GHz
Command                   cat $ISO|           <$ISO             Diff          Diff (pct)
Throughput \ Time (ms)    User     Sys Real   User   Sys Real   User Sys Real User       Sys Real
Baseline (cat)                    0 356    215      1  84     88    0 272  127          0 423  244
Low (bzip2)                  136184 896 136765 136728 160 137131 -545 736 -366         99 560   99
Medium (gzip)                 26564 788  26791  26332 108  26492  232 680  298        100 729  101
High (grep no_such_string)      264 392    483    216  84    304   48 308  179        122 466  158

Результаты показывают, что для низкой и средней пропускной способности стоимость составляет порядка 1%. Это хорошо в пределах неопределенности измерений, поэтому на практике нет никакой разницы.

Для высокой пропускной способности разница больше, и между ними есть четкая разница.

Это приводит к выводу: вы должны использовать < вместо cat | если:

  • сложность обработки похожа на простой grep
  • производительность важнее, чем удобочитаемость.

В противном случае не имеет значения, используете ли вы < или же cat |,

И, таким образом, вы должны давать награду UUoC только в том случае, если:

  • Вы можете измерить значительную разницу в производительности (опубликуйте свои измерения, когда вы даете награду)
  • производительность важнее, чем удобочитаемость.

Я думаю, что (традиционный способ) использование pipe немного быстрее; на моей коробке я использовал strace Команда, чтобы увидеть, что происходит:

Без трубы:

toc@UnixServer:~$ strace wc -l < wrong_output.c
execve("/usr/bin/wc", ["wc", "-l"], [/* 18 vars */]) = 0
brk(0)                                  = 0x8b50000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77ad000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=29107, ...}) = 0
mmap2(NULL, 29107, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb77a5000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\222\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1552584, ...}) = 0
mmap2(NULL, 1563160, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7627000
mmap2(0xb779f000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x178) = 0xb779f000
mmap2(0xb77a2000, 10776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb77a2000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7626000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb76268d0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb779f000, 8192, PROT_READ)   = 0
mprotect(0x804f000, 4096, PROT_READ)    = 0
mprotect(0xb77ce000, 4096, PROT_READ)   = 0
munmap(0xb77a5000, 29107)               = 0
brk(0)                                  = 0x8b50000
brk(0x8b71000)                          = 0x8b71000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=5540198, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7426000
mmap2(NULL, 1507328, PROT_READ, MAP_PRIVATE, 3, 0x2a8) = 0xb72b6000
close(3)                                = 0
open("/usr/share/locale/locale.alias", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=2570, ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb77ac000
read(3, "# Locale name alias data base.\n#"..., 4096) = 2570
read(3, "", 4096)                       = 0
close(3)                                = 0
munmap(0xb77ac000, 4096)                = 0
open("/usr/share/locale/fr_FR.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/fr_FR.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/fr_FR/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/fr.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/fr.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale/fr/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/fr_FR.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/fr_FR.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/fr_FR/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/fr.UTF-8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/fr.utf8/LC_MESSAGES/coreutils.mo", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/share/locale-langpack/fr/LC_MESSAGES/coreutils.mo", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=316721, ...}) = 0
mmap2(NULL, 316721, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7268000
close(3)                                = 0
open("/usr/lib/i386-linux-gnu/gconv/gconv-modules.cache", O_RDONLY) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=26064, ...}) = 0
mmap2(NULL, 26064, PROT_READ, MAP_SHARED, 3, 0) = 0xb7261000
close(3)                                = 0
read(0, "#include<stdio.h>\n\nint main(int "..., 16384) = 180
read(0, "", 16384)                      = 0
fstat64(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7260000
write(1, "13\n", 313
)                     = 3
close(0)                                = 0
close(1)                                = 0
munmap(0xb7260000, 4096)                = 0
close(2)                                = 0
exit_group(0)                           = ?

И с трубкой:

toc@UnixServer:~$ strace cat wrong_output.c | wc -l
execve("/bin/cat", ["cat", "wrong_output.c"], [/* 18 vars */]) = 0
brk(0)                                  = 0xa017000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap2(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb774b000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=29107, ...}) = 0
mmap2(NULL, 29107, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb7743000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/i386-linux-gnu/libc.so.6", O_RDONLY) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0p\222\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1552584, ...}) = 0
mmap2(NULL, 1563160, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb75c5000
mmap2(0xb773d000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x178) = 0xb773d000
mmap2(0xb7740000, 10776, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb7740000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb75c4000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75c48d0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb773d000, 8192, PROT_READ)   = 0
mprotect(0x8051000, 4096, PROT_READ)    = 0
mprotect(0xb776c000, 4096, PROT_READ)   = 0
munmap(0xb7743000, 29107)               = 0
brk(0)                                  = 0xa017000
brk(0xa038000)                          = 0xa038000
open("/usr/lib/locale/locale-archive", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=5540198, ...}) = 0
mmap2(NULL, 2097152, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb73c4000
mmap2(NULL, 1507328, PROT_READ, MAP_PRIVATE, 3, 0x2a8) = 0xb7254000
close(3)                                = 0
fstat64(1, {st_mode=S_IFIFO|0600, st_size=0, ...}) = 0
open("wrong_output.c", O_RDONLY|O_LARGEFILE) = 3
fstat64(3, {st_mode=S_IFREG|0664, st_size=180, ...}) = 0
read(3, "#include<stdio.h>\n\nint main(int "..., 32768) = 180
write(1, "#include<stdio.h>\n\nint main(int "..., 180) = 180
read(3, "", 32768)                      = 0
close(3)                                = 0
close(1)                                = 0
close(2)                                = 0
exit_group(0)                           = ?
13

Вы можете сделать некоторое тестирование с strace а также time команда с более и более длинными командами для хорошего бенчмаркинга.

Другие вопросы по тегам