Передача параметров через echo

На самом деле это единственный раздел про unix на этом форуме

Модераторы: /dev/random, Модераторы разделов

Ответить
Аватара пользователя
Stauffenberg
Сообщения: 2042
Статус: ☮ PEACE ☮
ОС: открытая и свободная

Передача параметров через echo

Сообщение Stauffenberg »

Всем привет

Вот такой вопрос: чем отличаются вызовы программы, при котором параметры передаются как обычно, т.е. prog arg1 arg2 arg3 и через echo, т.е. echo "arg1 arg2 arg3" | prog?

Для обработки и проверки параметров вот такой python-код:

Код: Выделить всё

#!/usr/bin/env python
import sys

print len(sys.argv)
print str(sys.argv)

И вывод соответственно:

Код: Выделить всё

./prog.py arg1 arg2 arg3
4
['./prog.py', 'arg1', 'arg2', 'arg3']


echo "arg1 arg2 arg3" | ./prog.py
1
['./prog.py']

Как перенаправить аргументы через pipe?
Labor omnia vincit

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” (Brian Kernighan)
Спасибо сказали:
Аватара пользователя
SLEDopit
Модератор
Сообщения: 4823
Статус: фанат консоли (=
ОС: GNU/Debian, RHEL

Re: Передача параметров через echo

Сообщение SLEDopit »

Stauffenberg писал(а):
31.05.2013 16:40
Вот такой вопрос: чем отличаются вызовы программы, при котором параметры передаются как обычно, т.е. prog arg1 arg2 arg3 и через echo, т.е. echo "arg1 arg2 arg3" | prog?
Тем что в первом случае аргументы передаются как аргументы, а во втором случае вы их пытаетесь пропихнуть через stdin и удивляетесь, что python их не видит.

echo "arg1 arg2 arg3" | prog == просто запуску prog без аргументов.
Stauffenberg писал(а):
31.05.2013 16:40
Как перенаправить аргументы через pipe?
Читать их из stdin'a в python?
sys.stdin в помощь.
UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity. © Dennis Ritchie
The more you believe you don't do mistakes, the more bugs are in your code.
Спасибо сказали:
Аватара пользователя
Stauffenberg
Сообщения: 2042
Статус: ☮ PEACE ☮
ОС: открытая и свободная

Re: Передача параметров через echo

Сообщение Stauffenberg »

SLEDopit
Спасибо, но по моему я не так выразился. Вопрос не о python, а о shell-интерпретаторе. Как мне передать вывод одной команды не на stdin второй, а именно как аргументы для второй?
Labor omnia vincit

"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.” (Brian Kernighan)
Спасибо сказали:
Аватара пользователя
/dev/random
Администратор
Сообщения: 5289
ОС: Gentoo

Re: Передача параметров через echo

Сообщение /dev/random »

Stauffenberg писал(а):
31.05.2013 17:15
SLEDopit
Спасибо, но по моему я не так выразился. Вопрос не о python, а о shell-интерпретаторе. Как мне передать вывод одной команды не на stdin второй, а именно как аргументы для второй?

man bash -> EXPANSION -> Command substitution
Если кратко, то:
ваш_скрипт $(команда_источник_параметров)
Спасибо сказали:
Аватара пользователя
sgfault
Сообщения: 586
Статус: -
Контактная информация:

Re: Передача параметров через echo

Сообщение sgfault »

И, если я правильно понял вопрос, xargs ведь тоже подойдет. Те

Код: Выделить всё

$ cat ./t.py
#!/usr/bin/env python
import sys

print len(sys.argv)
print str(sys.argv)
$ echo a b c | xargs ./t.py
4
['./t.py', 'a', 'b', 'c']

Но, обратите внимание, что xargs по дефолту:
- использует blank (те новая строка, пробел и, наверно, табуляция) для разделения аргументов в stdin.
- интерпретирует эскейп-последовательности обратный слеш, одинарные и двойные кавычки.

Чтобы это отключить, вы должны указать разделитель аргументов явно, например, так:

Код: Выделить всё

.. | xargs -d '\n' ..

Несколько примеров есть тут xargs, arguments separator and escapes. .

Upd. Небольшое исправление.

Upd2.
Вот еще пример:

Код: Выделить всё

$ echo \'a b\' c d | xargs ./t.py
4
['./t.py', 'a b', 'c', 'd']

здесь кавычки интерпретируются. А здесь нет:

Код: Выделить всё

$ echo \'a b\' c d | xargs -d'\n' ./t.py
2
['./t.py', "'a b' c d"]

Или, если нужно не интерпретировать кавычки и оставить разделителем пробел, то можно так:

Код: Выделить всё

$ echo \'a b\' c d | xargs -d' ' ./t.py
5
['./t.py', "'a", "b'", 'c', 'd\n']


Upd3.
Еще хотел бы обратить ваше внимение на всякий случай на разделение вывода команды после command substitution.

Если command substitution написано не в двойных кавычках, после него выполняется word splitting и pathname expansion. Те результат $() будет разделен на слова по символоам IFS (это word splitting), а затем спецсимолы типа * могут быть заменены на имена файлов в текущем каталоге (это pathname expansion):

Код: Выделить всё

$ ls
a.txt  t.py
$ ./t.py  $(echo 'b a*')
3
['./t.py', 'b', 'a.txt']


Соответственно, если pathname expansion вам не нужен, вы можете отключить его, включив опцию оболочки '-f' ('noglob'):

Код: Выделить всё

$ ( set -f; ./t.py  $(echo 'b a*') )
3
['./t.py', 'b', 'a*']


Если же пробел присутствует в самих аргументах (те по нему разделять вывод команды не надо), вы можете убрать его из IFS. Например, установив IFS в "новую строку":

Код: Выделить всё

$ ( set -f; IFS=$'\xa'; ./t.py  $(echo 'b a*') )
2
['./t.py', 'b a*']

Последний пример работает только в bash. Для sh замените $'\xa' на настоящую новую строку в кавычках:


Если же command substitution написан в кавычках, его результат всегда будет одним словом (ни word splitting, ни pathname expansion выполняться не будут):

Код: Выделить всё

$ ./t.py  "$(echo 'b a*')"
2
['./t.py', 'b a*']

Спасибо сказали:
Ответить