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

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

cat file | command

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

command < file

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

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

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

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

Ответ 1

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

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

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

Последняя причина более важна, поэтому я изложу ее в первую очередь. Когда я предлагаю трубопровод в качестве решения, я ожидаю, что его можно будет использовать повторно. Вполне вероятно, что конвейер будет добавлен в конце или объединен в другой конвейер. В этом случае наличие аргумента file для grep приводит к невозможности повторного использования, и вполне возможно, что это делается без сообщения об ошибке, если аргумент file существует. И. е. grep foo xyz | grep bar xyz | wc 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 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 file1 | grep foo поэтому мы нарушаем дух и cat и всемогущего Unix. Что ж, если бы это было так, тогда Unix потребовалась бы другая команда, чтобы прочитать вывод одного файла и выложить его на стандартный вывод (не разбивать его на страницы или что-то еще, просто наплевать на стандартный вывод). Таким образом, у вас может возникнуть ситуация, когда вы говорите " cat file1 file2 или " dog file1 и добросовестно не забываете избегать " cat file1 чтобы избежать получения награды, а также избегать " dog file1 file2 так как, надеюсь, дизайн " dog выдаст ошибку, если несколько файлов будут указано.

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

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

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

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

Ответ 2

Неа!

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

< 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)

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

Ответ 3

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

Использование:

cat "[email protected]" | command

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

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

Ответ 4

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

Это особенно актуально на таких сайтах, как Stack Overflow, ServerFault, Unix и Linux или любой из сайтов SE.

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

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

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


Обновление

Вот еще один UUOC, который я отправил в ответ на https://unix.stackexchange.com/a/301194/7696:

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" "[email protected]" | sqlplus -S sss/[email protected] | $filter
}

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

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

Ответ 5

Дополнительная проблема заключается в том, что канал может скрывать скрытую оболочку. В этом примере я заменю 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.

Ответ 6

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

Да,

   < 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 вполне подойдет. Для большинства вопросов использование кошки является ортогональным, не по теме, а не проблемой.

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

Ответ 7

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

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

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

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

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

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

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

Ответ 8

Я часто использую cat file | myprogram 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 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 только в том случае, если:

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

Ответ 9

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

Без трубы:

[email protected]:~$ 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)                           = ?

И с трубой:

[email protected]:~$ 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 с более длинными командами для хорошего бенчмаркинга.