Сообщить об ошибке.

Варианты передачи параметров в модуль sh

Содержание:


Передача позиционных параметров команде.

При передаче нескольких аргументов команде терминала, обернутой модулем sh, каждый аргумент должен быть отдельной строкой. Передача списка строк, так же будет ошибкой.

from sh import tar
# правильная передача аргументов
tar("cvf", "/tmp/test.tar", "/my/home/directory/")

При передаче аргументов, как указано ниже, будет возникать ошибка:

from sh import tar
# неправильная передача аргументов
tar("cvf /tmp/test.tar /my/home/directory")
# Traceback (most recent call last):
#  File "<stdin>", line 1, in <module>
# ...
#     raise exc
# sh.ErrorReturnCode_2: 
#   RAN: /bin/tar 'cvf /tmp/test.tar /my/home/directory'

Почему параметры должны быть отдельными строками?

Это сбивает с толку многих новых пользователей модуля sh. Они хотят сделать что-то подобное tar("cvf /tmp/test.tar /my/home/directory") и ожидают, что это просто сработает, Но вместо этого они получат сбивающее с толку сообщение об ошибке (как показано выше).

Причина, по которой они ожидают, что это сработает, заключается в том, что оболочки, такие как Bash, автоматически анализируют gthtlfyye. командную строку и разбивают ее на аргументы, прежде чем отправлять их в исполняемый файл. У них есть сложный набор правил, некоторые из которых представлены Python модулем shlex.

Даже если бы разработчики модуля хотели реализовать это в sh, то это уменьшило бы возможности пользователей параметризовать части аргументов. Им пришлось бы использовать строковую интерполяцию, которая по сути уродлива и подвержена ошибкам:

from sh import tar
tar("cvf {1} {2}".format("/tmp/tar1.tar", "/home/oh no a space")

В приведенном выше примере "/home/oh", "no", "a" и "space" будут отдельными аргументами для команды терминала tar, что приведет к неожиданному поведению программы. В принципе, каждая команда с позиционными параметрами должна была бы ожидать символов, которые могли бы сломать синтаксический анализатор.

Передача параметров команде по ключу.

Модуль sh поддерживает ключи короткой формы (например -a) и длинной формы (например --arg) в качестве параметров командной строки:

# вызывает "curl http://duckduckgo.com/ -o page.html --silent"
curl("http://duckduckgo.com/", o="page.html", silent=True)

# или если не использовать ключевые параметры
curl("http://duckduckgo.com/", "-o", "page.html", "--silent")

# вызывает "adduser amoffat --system --shell=/bin/bash --no-create-home"
adduser("amoffat", system=True, shell="/bin/bash", no_create_home=True)

# без использования ключевых параметров
adduser("amoffat", "--system", "--shell", "/bin/bash", "--no-create-home")

Как упорядочивать ключевые параметры командной строки?

Обычно этот вопрос задают, когда пользователь пытается выполнить что-то вроде следующей командной строки:

my-command --arg1=val1 arg2 --arg3=val3

Первая попытка, которую пользователь пытается сделать это :

import sh
sh.bash_command(arg1="val1", "arg2", arg3="val3")

Это не работает, потому что в Python позиционные аргументы, такие как arg2, не могут идти после ключевых аргументов.

Кроме того, вполне возможно, что --arg3=val3 предшествует --arg1=val1. Причина этого заключается в том, что **kwargs в функции является неупорядоченным отображением (словарем), и поэтому пары ключ-значение не гарантированно разрешаются в определенном порядке.

Таким образом, в данном случае, решение состоит в том, чтобы отказаться от использования ключевых аргументов и просто использовать необработанные позиционные аргументы:

sh.bash_command("--arg1=val1", "arg2", "--arg3=val3")

Параметры команды по умолчанию.

Часто встает необходимость переопределить параметры по умолчанию для всех команд терминала, запускаемых через модуль sh. Например, предположим, что надо объединять вывод всех команд в буфер io.StringIO.

import sh
from io import StringIO

buf = StringIO()

sh.ls("/", _out=buf)
sh.whoami(_out=buf)
sh.ps("auxwf", _out=buf)

Из кода видно, что постоянная передача _out=buf во все вызовы быстро надоедает. К счастью, можно создавать контексты выполнения, которые позволяют устанавливать аргументы по умолчанию для всех команд, порожденных из этого контекста:

import sh
from io import StringIO

buf = StringIO()
sh_buf = sh(_out=buf)

sh_buf.ls("/")
sh_buf.whoami()
sh_buf.ps("auxwf")

Теперь все, что запускается из sh_buf, будет посылать свои выходные данные в экземпляр буфера StringIO.

Контексты выполнения также могут быть импортированы, например, из модуля нижнего уровня buf.py:

# buf.py
import sh
from io import StringIO

buf = StringIO()
sh_buf = sh(_out=buf)

# cmd.py
from sh_buf import ls, whoami, ps

ls("/")
whoami()
ps("auxwf")

Передача входных данных команде через STDIN

Поток STDIN отправляется процессу непосредственно с помощью специального ключевого аргументы _in:

print(cat(_in="test"))
# test

Любая команда терминала, принимающая входные данные от STDIN, может быть использована следующим образом:

print(tr("[:lower:]", "[:upper:]", _in="sh is awesome"))
# SHISAWESOME

Следовательно пользователи не ограничены использованием только строк в качестве входных данных (но не параметров). Можно использовать файловый объект, очередь Queue или любую итерацию (список, словарь и т. д.):

stdin = ["sh", "is", "awesome"]
out = tr("[:lower:]", "[:upper:]", _in=stdin)

Выполнение собственных подмножеств команд.

Многие программы терминала имеют свои собственные подмножества команд, такие как git (например branch или checkout), svn (например update или status) и sudo (где любая команда, следующая за sudo, считается ее подкомандой). Модуль sh обрабатывает подкоманды через синтаксис Python доступа к атрибутам:

from sh import git, sudo

# выполнит "git branch -v"
print(git.branch("-v"))
# та же команда
print(git("branch", "-v"))

# выполнит "sudo /bin/ls /root"
print(sudo.ls("/root"))
# та же команда
print(sudo("/bin/ls", "/root"))

Обращение к подкомандам через синтаксис доступа к атрибутам - это в основном синтаксический сахар, который делает вызов некоторых программ концептуально более приятным.

Примечание. Если будете использовать sudo в качестве подкоманды, обязательно посмотрите раздел "Использование sudo в модуле sh".