Comments 36
Отправляете:
$ print -p abrakadabra1
Получаете:
$ read -p var; echo $var
bbrbkbdbbrb1
У вас буква a сломалась
для (GNU Coreutils) 8.21 опции -u нет, поэтому пример, где «процедура записи/чтения» не отработает, а результат будет виден только после закрытия дескрипторов.
какая версия tr?
https://www.freebsd.org/cgi/man.cgi?tr
поэтому пример, где «процедура записи/чтения» не отработает
Вам стоить прочитать всю статью, а не урывок в конце и решение найдётся.
Translate, squeeze, and/or delete characters from standard input, writing to standard output.
-c, -C, --complement
use the complement of SET1
-d, --delete
delete characters in SET1, do not translate
-s, --squeeze-repeats
replace each input sequence of a repeated character that is listed in SET1 with a single occurrence of that character
-t, --truncate-set1
first truncate SET1 to length of SET2
--help display this help and exit
--version
output version information and exit
К тому же, вы нигде не упоминали, что это под freebsd. Покажите мне, с какой версии под линухом эта опция? Хамить я тоже умею, заметили?
Хамить я тоже умею, заметили?
То что это Ваш стиль общения исключительно Ваше дело.
А статью Вам действительно стоит прочитать всю, тогда Вы найдёте ответ на:
вы нигде не упоминали, что это под freebsd.
Хоть это и не имеет прямого отношения к вопросам статьи, отмечу, что все нижеприведённые примеры сделаны на
$ uname -opr FreeBSD 10.1-STABLE amd64
И на
И что конкретно я должен был прочитать?
Хотя бы
Разумеется, если данное поведение нас не устраивает, его можно изменить, например используя stdbuf
$ coproc stdbuf -oL -i0 tr a b
Тема зачем?
не раскрыта.
PS:
Ищущий да найдёт. И отпишется, чтобы мы тоже знали)
* Никак нельзя сделать не на баше
* Подготовка данных разбита на шаги
* А выполнение при этом не бесплатное (т.е. занимает время)
То это неплохой способ уменьшить общее время выполнения скрипта.
Как простой пример — persistent connection к БД.
Как простой пример — persistent connection к БД.
Андрей, хоть это и единственное найденное применение описанное в статье, на самом деле я при первой возможности ушёл от этого решения.
Причины:
— умирание сопроцесса при «битых» запросах (как следствие необходимость проверки жизнеспособности сопроцесса);
— потеря неизвлечённых данных при этом;
— геморойная обработка данных при извлечении и сопоставление их с запросом.
Всё-таки работа с БД — это не стихия *sh.
процесс 1
mkpipe testpipe
echo abrakahabra >> testpipe
процесс 2
cat testpipe
И этот вариант, я даже несколько раз использовал. Новый функционал исключительно для создания «анонимного пайпа»?
mkpipe
Извините, а что это за зверь такой?
Ох сорри, mkfifo, опечатался.
Работает именно так, как описано в статье, только это есть даже не просто в каком-то конкретно взятом шелле, а вообще просто фича всех POSIX файловых систем, можно пользоваться откуда угодно.
На диске лежит только имя файла, на самом деле вся информация передается через буферы.
mkpipe testpipe
Вероятно речь об mkfifo?
echo abrakahabra >> testpipe
cat testpipe
Это только каналы ввода/вывода, а где фоновый процесс?
Вариант реализации посредством mkfifo в статье приведен
$ mkfifo in out
$ tr -u a b <in >out &
$ exec 3> in 4< out
$ echo abrakadabra1 >&3
$ echo abrakadabra2 >&3
$ echo abrakadabra3 >&3
$ read var <&4 ; echo $var
bbrbkbdbbrb1
$ read var <&4 ; echo $var
bbrbkbdbbrb2
$ read var <&4 ; echo $var
bbrbkbdbbrb3
во ВСЕХ шеллах при помощи pipe
Разумеется, приведенный вариант не универсален и не будет работать во всех шеллах. Хотя, скорее всего, во всех Борн-шеллах должен отработать.
У FIFO есть много недостатков:
- FIFO нужно где‐то создать. Предположительно, вам придётся заморочиться с
mktemp -d
. - FIFO нужно потом ещё и удалить. Причём удалить независимо от того, успешно ли завершился скрипт. Хотя, в принципе, можно удалить сразу после
exec
. - FIFO не должен быть перехвачен другой программой: к примеру, другим процессом того же скрипта. Он особенно не должен быть доступен для других пользователей. Ещё один повод использовать именно
mktemp -d
.
Последний (и, кажется, единственный) раз, когда я попытался использовать сопроцессы в zsh я пожалел, что сопроцесс может быть только один (и ещё вроде были какие‐то проблемы). FIFO я не использовал вообще никогда, если мне нужно что‐то подобное я лучше либо перепишу всё так, что мне это не нужно будет (обычно process substitution и стандартного перенаправления через |
хватает за глаза), либо перепишу на Python.
В bash Linux — если сопроцессор завершается до начала считывания, то теряем вывод полученный от него через "${COPROC[0]}".
$ ls -Al
total 20360
-rw-rw-r--. 1 ilia ilia 20834292 авг 15 15:46 1
drwxrwxr-x. 2 ilia ilia 4096 авг 15 15:10 proba
drwxrwxr-x. 2 ilia ilia 4096 авг 15 15:10 proba2
drwxrwxr-x. 2 ilia ilia 4096 авг 15 15:10 proba3
$ coproc ls -Al .
[1] 16739
[1]+ Done coproc COPROC ls --color=auto -Al .
$ echo "${COPROC[0]}"
${COPROC[0]} — больше нет, получить неоткуда. Неудобно. Легче что-то другое придумать, у тех же FIFO такого нет.
А если в канал не помещается весь вывод, то уже лучше, сопроцессор ждет освобождения места в буфере для продолжения и не завершается. Но хвост вывода можем потерять.
$ coproc ls -alR /
[1] 16797
$ echo "${COPROC[0]}"
63
Выглядит как ошибка, в man bash
я предупреждений по этому поводу не нашёл. zsh и ksh таким не страдают, так что никаких оправданий вроде «а у этих такая же фигня» не может быть.
Вы пробовали с этим вопросом пойти в bug tracker bash’а?
Вы пробовали с этим вопросом пойти в bug tracker bash’а?
Нет, не пробовал, т.к. об этой штуке узнал пару часов назад. Для меня не нужная вещь. Хотя выглядит действительно как ошибка. На всякий случай оставлю, вдруг кому-нибудь пригодится:
$ cat /etc/redhat-release
CentOS Linux release 7.2.1511 (Core)
$ bash --version
GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu)
$ uname -a
Linux 3.10.0-327.28.2.el7.x86_64 #1 SMP Wed Aug 3 11:11:39 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
ps afx | grep [6]053
Этот прием надо запомнить!
Не нужно, вы не в BSD. ps -p 6053
. Если в совете предполагается пропустить вывод ps
через grep
на linux
, то, скорее всего, этот совет не оптимальный и grep
на самом деле трогать не нужно.
Хотя, судя по man ps (BSD) там тоже должно работать.
Я знаю, зачем в строке grep
[]
. Я не знаю, зачем вообще нужен grep
здесь, если есть ps -p
, позволяющий обойтись без grep
. И есть ps -C
позволяющий то же самое для нахождения конкретных процессов по имени исполняемого файла. grep
нужен в редких случаях, когда у вас 100500 процессов вида myapp --foo bar
и вам хочется отыскать среди них PID того, что запущен с --foo baz
. Или когда вы представляете, что вам нужно лишь приблизительно (к примеру, браузеры имеют нехорошую привычку запускаться одной командой (e.g. vivaldi), а в списке висеть в виде другой (vivaldi-bin в примере), но это относится не только к vivaldi и даже не только к chromium-based).
ps -p 6053
вам покажет данные только для процесса с PID 6053 и безо всяких паразитных строчек (не считая заголовка), которые нужно будет исключать всякими хаками. Или покажет только заголовок, если процесс уже завершился (заголовок можно убрать, если нужно: ps hp 6053
или ps --no-headers -p 6053
).
Ещё: вот будет у вас в фоне запущен mpv
с именем серии с хэшем, содержащим 6053, вы его увидите, несмотря на ваш трюк с grep. И процесс с PID 16053 увидите. И процесс, который работает 6053 часов. И процесс на псевдотерминале pts/6053. С PID 6053 такое маловероятно, но PID бывают и маленькими — они вообще назначаются циклически или случайно (в зависимости от настроек ядра ОС). При использовании ps -p 6053
ничего из вышеперечисленного вы не увидите.
Ну и, конечно, ps -p 6053
требует меньше нажатий клавиш, чем ps afx | grep [6]053
. Не забудьте также, что в zsh с такими привычками вы имеете хорошие шансы увидеть zsh: no matches found: [6]053
. Bash тоже можно так настроить. Трюк пропадёт в никуда, если в каталоге есть файл 6053
. При других настройках оболочки ваша команда выдаст
Использование: grep [ПАРАМЕТР]… ШАБЛОН [ФАЙЛ]…
Запустите «grep --help» для получения более подробного описания.
([6]053
было раскрыто в «ничего», потому что такого файла нет). Из‐за возможности таких фокусов никогда не полагайтесь на то, что провальные glob expression’ы будут заменены на самих себя. Хотите передать grep
[6]053
— пишете '[6]053'
.
Я лишь усомнился, что Михаила заинтересовал "|" и ещё более сомнительно, что его заинтересовал man ps.
ps -p 6053 вам покажет данные только для процесса с PID 6053
Спасибо, конечно, но я тоже знаю о существании ключа "-p" у ps.
При этом много чаще пользуюсь именно символьным преобразованием, так как это универсальнее.
В статье лучше написать ps -p
. В любом случае, символьное преобразование взять в кавычки.
У меня привычки куда как дальше от работающих «по‐умолчанию»: вашу команду я бы написал как ps afx G '[6]053'
и меня бы никто не понял (включая любую ненастроенную оболочку): zsh имеет такую замечательную вещь, как «глобальные alias’ы», позволяющую заменять не только команды. Конкретно G
раскрывается в | grep
*, есть и другие вроде alias -g L='| less'
. Разумеется, это дало два набора привычек: «для скриптов» (там alias’ы не работают, не говоря уж о том, что часть скриптов мне приходится писать для POSIX sh, а не zsh) и «для печати в командной строке». При общении предпочитается именно последнее.
А у скриптов есть и ещё одна особенность: во‐первых, лучше написать всё так, чтобы не вылавливать потом баги, чем написать какое‐нибудь while ps afx | grep "[6]053"
и внезапно обнаружить «бесконечный цикл» на ровном месте, т.к. какой‐то процесс попал на pts/6053. Во‐вторых, PID в этом случае окажется в переменной и доставать по отдельности первый и остальные символы будет как‐то сложновато (я к тому, что решение, оперирующее с цельным значением предпочтительнее решения, предполагающего разбиение его на части: в POSIX нет ни индексации строк (${PID[1]}
или ${PID:0:0}
), ни даже ${PID//sub/rep}
).
* С некоторых пор (после этой статьи) я немного подумал и теперь он раскрывается в | nocorrect noglob grep
(то же, но zsh не будет пытаться раскрыть [6]053
).
https://habrahabr.ru/post/229501/#comment_7770191
Сопроцессы: -что, -как, -зачем?