LinuxForum.Fans
Тема

Объединение команд и обработка выходных данных в shell

Автор: DiabloPC 24 сообщений 2455 просмотров
15.03.2017 05:36 #421320

Оставлю это здесь не ради темы, а в качестве заметки ;)
Поэтому попрошу холиварню здесь не разводить, ну а если есть чем еще дополнить - welcome =)



Объединение команд это очень полезная операция которую я сам очень часто применяю в терминале.
Допустим вам нужно куда-то срочно уйти, но вы хотите скомпилировать что-либо. Вы знаете, что сначала нужно ввести [console=inline]# ./configure[/console] потом [console=inline]# make[/console] и только потом [console=inline]# make install[/console], при том окончание работы make иногда приходиться ждать час, а то и поболее. В таких моментах придет на помощь объединение команд.
Зная этот прием, вы введете [console=inline]# ./configure && make && make install[/console] и уйдете по своим делам в то время как все нужные команды выполняться сами и полностью завершат компиляцию.
Можно даже добавить команду shutdown -h now в конец для отключения компьютера после выполнения всех операций.


Последовательное выполнение команд вне зависимости от исхода работы предыдущей. [ ; ]Выполнить сколько угодно команд последовательно можно путем разделение команд символом ; (точка с запятой).
Пример: [console=inline]# ./configure ; make ; make install[/console] -выполнятся все команды последовательно вне зависимости от исхода предыдущих.
То есть, если в ./configure будет выведено сообщение об ошибки, то интерпретатор все равно попробует выполнить make и make install.


Последовательное выполнение команд при условии успешного завершения предыдущих. [ && ]Символы && (два амперсанда) позволяют выполнять действие подобные предыдущей конструкции, но при не успешном завершении команды интерпретатор прекратит выполнение всего сценария.
Например: [console=inline]# ./configure && make && make install[/console] -если в ./configure будет ошибка, то последующие команды не будут исполняться. Если же все прошло удачно, то начнут выполняться make и make install притом если в make будет ошибка, то make install выполняться тоже не будет.


Выполнение команды, если предыдущая завершилась ошибкой. [ || ]Можно выполнить команды не только при успешном завершении предыдущей, но и при ошибочном завершении предыдущей с помощью символов || (две прямых черты).
Пример: [console=inline]# make install || echo 'Ошибка!'[/console] -выведется слово ошибка при неудачном завершении команды make install, иначе это слово выводиться не будет.


Использование выходных данных одной команды при вызове другой. [ $() ] [ ` ` ]Давайте посмотрим на пример: [console=inline]# touch $(uname -r)[/console]
Эта команда создаст файл имя которого будет версия текущего ядра linux.
Команде touch передается с помощью конструкции $() команда выходные данные которой можно использовать для аргумента первой команды.
Это можно записывать в другой форме, иногда так бывает удобнее: [console=inline]# touch `uname -r`[/console]Только кавычки здесь должны быть те, который на букве 'Ё', крайне слева вверху.


Запись результатов выполнения команды в файл. [ > ]Это очень удобная функция! С помощью символа > (больше) можно записать вывод команды в текстовый файл.
Пример: [console=inline]# ls -R /home > home.txt[/console] -эта команды запишет в файл home.txt все папки и файлы находящиеся в домашнем каталоге и подкаталогах. В стандартный вывод ничего не выведется - все пойдет исключительно в файл.
Иногда для этого приходится указывать явно номер файлового дескриптора вывода: 1 - SYSOUT, 2 - SYSERR
Записать сообщения об ошибках в файл: [console=inline]# xxx 2>home.txt[/console]
Объединить вывод программы с сообщениями об ошибках, и всё вместе это отправить в файл: [console=inline]# xxx 2>&1 >home.txt[/console]В такой записи & - обязателен, это специальная синтаксическая форма ... иначе ошибки бы записывались в файл с именем "1".


Использование дозаписи [ >> ]Чтобы файл не очищался, а новые данные добавлялись в конец надо использовать символы >> (два знака больше)
Пример: [console=inline]# ls >> home.txt[/console] -при всех последующих вызовах такой команды новые данные будут добавляться в конец файла.

15.03.2017 10:20 · отредактировано #421330
"DiabloPC" написал:

Давайте посмотрим на пример:
# touch $(uname -r)

Это можно записывать в другой форме, иногда так бывает удобнее:
[console]$ touch `uname -r`[/console]
Только кавычки здесь должны быть те, который на букве 'Ё', крайне слева вверху.


Olej, Добавил в шапку.
15.03.2017 10:24 #421333

Olej, В курсе =) Но никак не пойму в чем удобство? Как по мне то вариант [ $() ] более, даже не знаю как обозвать... более наглядный, чтоль...
По крайней мере мне его удобнее пользовать... А результат, собственно тот-же ;)
ЗЫ
А еще в этом варианте можно завернуть вот так: [ $( $() ) ], а с кавычками такое не прокатит.

15.03.2017 10:36 #421334
"DiabloPC" написал:
Пример:
# ls -R /home > home.txt -эта команды запишет в файл home.txt

Иногда для этого приходится указывать явно номер файлового дескриптора вывода: 1 - SYSOUT, 2 - SYSERR

Записать сообщения об ошибках в файл:
[console]
$ xxx 2>home.txt
[/console]

Объединить вывод программы с сообщениями об ошибках, и всё вместе это отправить в файл:
[console]
$ xxx 2>&1 >home.txt
[/console]
В такой записи & - обязателен, это специальная синтаксическая форма ... иначе ошибки бы записывались в файл с именем "1".
Добавлено: 15.03.2017 10:36:20

"DiabloPC" написал:
# ./configure ; make ; make install -выполнятся все команды последовательно вне зависимости от исхода предыдущих.

Если говорить о последовательном выполнении, то нужно бы, для сравнения, упомнить и о конвейерах - параллельном выполнении программ:
[console]
$ prog1 | prog2 | prog3
[/console]
Здесь:
- в отличие от ';' prog1, prog2, prog3 выполняются параллельно, одновременно...
- выход (SYSOUT) каждого процесса (кроме последнего) замыкается на вход (SYSOUT) предыдущего.

15.03.2017 10:42 #421338
"DiabloPC" написал:
Последовательное выполнение команд вне зависимости

Это лишь более компактная запись трех команд в одной строке. В скриптах лучше такого избегать для повышения читабельности.
Добавлено: 15th Mar 2017 10:42:34

"Olej" написал:
prog1 | prog2 | prog3

Результат работы первой команды передается на стандартный ввод (stdin) второй программы, а результат работы второй передается на stdin третьей. Это называется pipe ("труба").

15.03.2017 10:48 #421344

yars, В скриптах - понятно что лучше так не делать.. Там строчек много, можно и в разных, по человечески, написать. А это именно для командной строки применимо, собственно все началось с того что решил кинуть слив бэкапа и пойти спать, но с учетом того что бэкапы я делаю с помощью dd_rescue --sparse нужно было предварительно забить свободное пространство на диске нулями, что само по себе дело не очень быстрое, и только потом запускать копирование даных. Самый простой способ сделать это - dd_rescue /dev/zero /zerofile && rm /zerofile, но тут встал вопрос: && ведь обрывает цепочку при ошибках в завершении предыдущей команды. Блин, а как сделать чтобы оно продолжило выполнять все остальное? Ну не пользовал я это никогда. Ну ессно гуголь в помощь, но, как ни странно, на это ушло гараздо больше времени чем я предполагал. Вот и решил тут оставить, дабы всегда под рукой было, ну и мож еще кому пригодится =)

15.03.2017 10:50 #421346
"yars" написал:
Это называется pipe ("труба").

В русскоязычной литературе это называется "конвейер".
Но важное здесь, что подчеркнуть нужно, что prog1, prog2, prog3 здесь выполняются параллельно.

15.03.2017 10:53 #421347
"DiabloPC" написал:
амый простой способ сделать это - dd_rescue /dev/zero /zerofile && rm /zerofile, но тут встал вопрос: && ведь обрывает цепочку при ошибках в завершении предыдущей команды.

Эмм... а такой вараинт разве не парокатит?
dd_rescue /dev/zero /zerofile ; rm /zerofile
В любом случае выполнисят 2я команда после завершения первой

15.03.2017 10:55 #421348

"Olej" написал:
конвейерах - параллельном
Ну немного разные понятия.

В конвеере они выполняются последавательно, передавая STDOUT, на STDIN следующей програмы.

А паралельно они выполняются через & (в фоновом режиме) >> [highlight=#000]# prog1 & prog2 & prog3[/highlight]
Добавлено: 15th Mar 2017 9:55:03 am

"i2ks" написал:
Эмм... а такой вараинт разве не парокатит?
Так в том то и дело что прокатит, вот только никогда не пользовался - пришлось искать как это делается. )) Как-то так сложилось что всегда пользовал цепочки только с удачным завершением ;)
15.03.2017 11:11 #421349
"DiabloPC" написал:
В конвеере они выполняются последавательно,

В конвейере программы выполняются параллельно.

15.03.2017 11:12 #421350

"Olej" написал:
В конвейере программы выполняются параллельно.
Как они могут выполняться параллельно если каждая последующая команда ждет результатов работы предыдущей?
15.03.2017 11:13 #421351
"DiabloPC" написал:
Как они могут выполняться параллельно

Вот так *OK*

"DiabloPC" написал:
если каждая последующая команда ждет результатов работы первой?

Никто никого не ждёт.

15.03.2017 11:18 #421352

Olej,

"вот довольно наглядно показано выполнение конвеера. И где же здесь параллельность?"

15.03.2017 11:28 · отредактировано #421353
"DiabloPC" написал:
В конвеере они выполняются последавательно, передавая STDOUT, на STDIN следующей програмы.

Ну как же так? o_O
Вы таки сами себе так сильно противоречите (как сказали бы в Одессе):
- если бы процессы выполнялись последовательно...
- то при выполнении предыдущей - ещё нет никакого STDIN последующей ... некуда ничего передавать...
- а после завершения предыдущей - уже нет никакого STDOUT, он уже закрыт и ликвидирован ... откуда передавать.

Конвейеры в коде реализуются через POSIX API pipe, который может работать только между родственными параллельными процессами.
Добавлено: 15.03.2017 11:21:03

"DiabloPC" написал:
Olej,

Учи матчасть! \m/

Добавлено: 15.03.2017 11:23:16

"DiabloPC" написал:
В конвеере они выполняются последавательно, передавая STDOUT, на STDIN следующей програмы.

А та глупость, которую вы имеете в виду, записывалась бы так:
[console]
$ prog1 >xxx ; prog2 <xxx
[/console]

DiabloPC написал:
&quot;вот довольно наглядно показано выполнение конвеера. И где же здесь параллельность?&quot;

[console]
[olej@dell 14]$ cat | tee x | tee y
...
[/console]
[console]
[olej@dell own_LSD2_12]$ ps -A | tail -n30
...
10150 pts/2 00:00:00 cat
10151 pts/2 00:00:00 tee
10152 pts/2 00:00:00 tee
10189 pts/11 00:00:00 ps
10190 pts/11 00:00:00 tail
...
[/console]
Как легко видеть, это скопировано из выполняющихся терминалов ... а не пересказано от большого ума. *DRINK*

15.03.2017 12:09 #421355

"Olej" написал:
Учи матчасть!
Походу прийдется =)
15.03.2017 12:27 · отредактировано #421356
"DiabloPC" написал:
Походу прийдется =)

Зачем же вы удалили приводимый вами пример?
Пример, по-моему, как-раз был хорош.

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

15.03.2017 12:41 #421357
"Olej" написал:
Пример, по-моему, как-раз был хорош.
Неособо.... Там, если вдуматься в логику работы получается немного не то...
[console]echo $i | grep -E [0-9] && sleep1[/console] Здесь получается pipe, затем, после успешного выполнения одного прохода, он завершается и выполняется sleep, а затем создается новый конвеер....
...по идее так....
Добавлено: 15th Mar 2017 11:35:37 am

"Olej" написал:
непонятно что писать в контекст поиска
вотЬ вотЬ, собственно из-за этого у меня минут 20 и занял поиск того что в шапке %)
Добавлено: 15th Mar 2017 11:41:40 am

"Olej" написал:
Как легко видеть, это скопировано из выполняющихся терминалов ... а не пересказано от большого ума.

Вот, придумал как сделать более наглядный пример параллельности в цикле:
[console]for i in 1 2 3 4 5; do $(echo echo $i; sleep 1) | grep -E [0-9]; done[/console]

15.03.2017 14:00 #421362
"DiabloPC" написал:
Вот, придумал как сделать более наглядный пример параллельности:

http://www.gnu.org/software/parallel/ наглядней не бывает :-)

15.03.2017 14:36 #421363
i2ks написал:
[quote="DiabloPC"]Вот, придумал как сделать более наглядный пример параллельности:

http://www.gnu.org/software/parallel/ наглядней не бывает :-)[/quote]
Да нет - это совершенно о другом:


GNU parallel is a shell tool for executing jobs in parallel ...

Это об отдельной частной утилите, никакого отношения к обсуждаемой теме не имеющей.

15.03.2017 14:49 #421364

"Olej" написал:
Да нет - это совершенно о другом:
я к тому, то что можно посмотреть как там это реализованно.
Там же все на перле на скольо я вижу.
Войдите или зарегистрируйтесь, чтобы ответить.