System administration
*nix
Shells
Comments 36
0
Хммм, возможно с помощью этого можно будет упростить некоторые мои монструозные скрипты… Интересная идея. А то та монструозность что есть вообще чудо что работает.
+7
У меня уже Chromium с Atom.io сжирают 80% оперативы, если ещё shell будет на js, то в чём же мне killall chromium && killall atom выполнять?
-1
Мне кажется что когда вы отправляете сообщение, то получаете какую-то абракадабру:
Отправляете:
$ print -p abrakadabra1

Получаете:
$ read -p var; echo $var
bbrbkbdbbrb1

У вас буква a сломалась
+5
Очевидно, в фоне выполняется
tr -u a b

который используется для замены всех a на b. Так что всё работает как и ожидается :)
-7
какая версия tr?
для (GNU Coreutils) 8.21 опции -u нет, поэтому пример, где «процедура записи/чтения» не отработает, а результат будет виден только после закрытия дескрипторов.
+4
какая версия tr?

https://www.freebsd.org/cgi/man.cgi?tr
поэтому пример, где «процедура записи/чтения» не отработает

Вам стоить прочитать всю статью, а не урывок в конце и решение найдётся.
-10
Да ну, прям всю статью? И что конкретно я должен был прочитать? А man к функциям я читать умею и справку вызывать.
man tr
DESCRIPTION
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. Покажите мне, с какой версии под линухом эта опция? Хамить я тоже умею, заметили?
+7
Хамить я тоже умею, заметили?

То что это Ваш стиль общения исключительно Ваше дело.

А статью Вам действительно стоит прочитать всю, тогда Вы найдёте ответ на:
вы нигде не упоминали, что это под freebsd.

Хоть это и не имеет прямого отношения к вопросам статьи, отмечу, что все нижеприведённые примеры сделаны на

$ uname -opr
FreeBSD 10.1-STABLE amd64


И на
И что конкретно я должен был прочитать?

Хотя бы
Разумеется, если данное поведение нас не устраивает, его можно изменить, например используя stdbuf

$ coproc stdbuf -oL -i0 tr a b

0
Тема раскрыта) Автор честно сказал, что не знает ответа на этот вопрос.

PS:
Ищущий да найдёт. И отпишется, чтобы мы тоже знали)
0
Если так получилось, что:
* Никак нельзя сделать не на баше
* Подготовка данных разбита на шаги
* А выполнение при этом не бесплатное (т.е. занимает время)

То это неплохой способ уменьшить общее время выполнения скрипта.

Как простой пример — persistent connection к БД.
0
Как простой пример — persistent connection к БД.

Андрей, хоть это и единственное найденное применение описанное в статье, на самом деле я при первой возможности ушёл от этого решения.
Причины:
— умирание сопроцесса при «битых» запросах (как следствие необходимость проверки жизнеспособности сопроцесса);
— потеря неизвлечённых данных при этом;
— геморойная обработка данных при извлечении и сопоставление их с запросом.
Всё-таки работа с БД — это не стихия *sh.
0
Хм. Но зачем нужны сопроцессы, если этот же функционал реализовывается немного проще, во ВСЕХ шеллах при помощи pipe:
процесс 1
mkpipe testpipe
echo abrakahabra >> testpipe

процесс 2
cat testpipe


И этот вариант, я даже несколько раз использовал. Новый функционал исключительно для создания «анонимного пайпа»?
0
Это стандарт для файловых систем Posix — создание файла-потока, в который один процесс может писать, а другой читать.

Ох сорри, mkfifo, опечатался.

Работает именно так, как описано в статье, только это есть даже не просто в каком-то конкретно взятом шелле, а вообще просто фича всех POSIX файловых систем, можно пользоваться откуда угодно.
На диске лежит только имя файла, на самом деле вся информация передается через буферы.
+1
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

Разумеется, приведенный вариант не универсален и не будет работать во всех шеллах. Хотя, скорее всего, во всех Борн-шеллах должен отработать.
+1

У FIFO есть много недостатков:


  1. FIFO нужно где‐то создать. Предположительно, вам придётся заморочиться с mktemp -d.
  2. FIFO нужно потом ещё и удалить. Причём удалить независимо от того, успешно ли завершился скрипт. Хотя, в принципе, можно удалить сразу после exec.
  3. FIFO не должен быть перехвачен другой программой: к примеру, другим процессом того же скрипта. Он особенно не должен быть доступен для других пользователей. Ещё один повод использовать именно mktemp -d.

Последний (и, кажется, единственный) раз, когда я попытался использовать сопроцессы в zsh я пожалел, что сопроцесс может быть только один (и ещё вроде были какие‐то проблемы). FIFO я не использовал вообще никогда, если мне нужно что‐то подобное я лучше либо перепишу всё так, что мне это не нужно будет (обычно process substitution и стандартного перенаправления через | хватает за глаза), либо перепишу на Python.

0
Здравствуйте.
В 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

0

Выглядит как ошибка, в man bash я предупреждений по этому поводу не нашёл. zsh и ksh таким не страдают, так что никаких оправданий вроде «а у этих такая же фигня» не может быть.


Вы пробовали с этим вопросом пойти в bug tracker bash’а?

0
Вы пробовали с этим вопросом пойти в 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
0

У меня то же самое в bash-4.3_p42-r1, Gentoo amd64. Хотя это не последняя версия в portage: есть ещё «нестабильная» 4.3_p46 и «замаскированная» 4.4_rc1.

+2

Не нужно, вы не в BSD. ps -p 6053. Если в совете предполагается пропустить вывод ps через grep на linux, то, скорее всего, этот совет не оптимальный и grep на самом деле трогать не нужно.

+2
Вилимо имелось ввиду преобразование символьного класса и исключение лишней строки из вывода grep
0

Я знаю, зачем в строке 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'.

0
Павел, Ваша экспрессия «в никуда».
Я лишь усомнился, что Михаила заинтересовал "|" и ещё более сомнительно, что его заинтересовал man ps.
ps -p 6053 вам покажет данные только для процесса с PID 6053

Спасибо, конечно, но я тоже знаю о существании ключа "-p" у ps.
При этом много чаще пользуюсь именно символьным преобразованием, так как это универсальнее.
0

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

0
Согласен и с тем и с тем, но десятилетняя привычка и большая вольность с закавычиванием в c-шеллах делают свое дело.
0

У меня привычки куда как дальше от работающих «по‐умолчанию»: вашу команду я бы написал как 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).

Only those users with full accounts are able to leave comments., please.