Есть ли способ узнать, как пользователь вызвал программу из bash?

Вот проблема: у меня есть этот сценарий foo.py, и если пользователь вызовет его без параметра --bar, я хотел бы отобразить следующее сообщение об ошибке:

Please add the --bar option to your command, like so:
    python foo.py --bar

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

  • Возможно, они использовали python foo.py, как в примере
  • Возможно, они использовали /usr/bin/foo.py
  • У них может быть псевдоним оболочки frob='python foo.py', и на самом деле они запускаются frob
  • Возможно, это даже псевдоним git flab=!/usr/bin/foo.py, и они использовали git flab

В любом случае я бы хотел, чтобы сообщение отражало, как пользователь вызвал команду, чтобы приведенный мной пример имел смысл.

sys.argv всегда содержит foo.py, а /proc/$$/cmdline ничего не знает о псевдонимах. Мне кажется, что единственным возможным источником этой информации был бы сам bash, но я не знаю, как его спросить.

Любые идеи?

ОБНОВЛЕНИЕ Как насчет того, чтобы ограничить возможные сценарии только перечисленными выше?

ОБНОВЛЕНИЕ 2. Многие люди написали очень хорошее объяснение того, почему это невозможно в общем случае, поэтому я хотел бы ограничить свой вопрос следующим:

При следующих предположениях:

  • Скрипт запускался интерактивно из bash
  • The script was start in one of these 3 ways:
    1. foo <args> where foo is a symbolic link /usr/bin/foo -> foo.py
    2. git foo где alias.foo =! / Usr / bin / foo в ~/.gitconfig
    3. git baz где alias.baz =! / Usr / bin / foo в ~/.gitconfig

Есть ли способ отличить 1 от (2,3) внутри сценария? Есть ли способ отличить 2 от 3 внутри сценария?

Я знаю, что это долгий путь, поэтому пока принимаю ответ Чарльза Даффи.

ОБНОВЛЕНИЕ 3. На данный момент наиболее многообещающий ракурс был предложен Чарльзом Даффи в комментариях ниже. Если я смогу заставить своих пользователей иметь

trap 'export LAST_BASH_COMMAND=$(history 1)' DEBUG

в их .bashrc, то я могу использовать в своем коде что-то вроде этого:

like_so = None
cmd = os.environ['LAST_BASH_COMMAND']
if cmd is not None:
    cmd = cmd[8:]  # Remove the history counter
    if cmd.startswith("foo "):
        like_so = "foo --bar " + cmd[4:]
    elif cmd.startswith(r"git foo "):
        like_so = "git foo --bar " + cmd[8:]
    elif cmd.startswith(r"git baz "):
        like_so = "git baz --bar " + cmd[8:]
if like_so is not None:
    print("Please add the --bar option to your command, like so:")
    print("    " + like_so)
else:
    print("Please add the --bar option to your command.")

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


person itsadok    schedule 12.07.2018    source источник
comment
Может хватит history 1?   -  person Aaron    schedule 12.07.2018
comment
Если --bar является обязательным, как насчет того, чтобы всегда добавлять его внутри себя и предоставлять --no-bar более опытным пользователям, которые этого не хотят и знают, как добавлять аргументы?   -  person Mark Setchell    schedule 12.07.2018
comment
@MarkSetchell, здесь моя попытка обобщения имела неприятные последствия. Мой текущий вариант использования касается сценария, который завершается, но хочет сказать пользователю, что они могут продолжить --continue. Вроде как когда git rebase попадает в конфликт. Значит, твоя идея у меня не сработает.   -  person itsadok    schedule 12.07.2018
comment
@ Аарон да! Но как мне получить доступ к истории родительского процесса bash?   -  person itsadok    schedule 12.07.2018
comment
Я не уверен, что вы имеете в виду, история записывает, что пользователь вводит в текущую оболочку (и другие оболочки, история которых сохраняется в ~ / .bash_history). Это не будет записывать выполнение вашего скрипта во многих ситуациях, например, когда скрипт вызывается из другого (будет записан только скрипт, вызванный пользователем) или из cron или других служб. Он также может быть отключен пользователем.   -  person Aaron    schedule 12.07.2018
comment
@Aaron история обычно сохраняется только при выходе из bash, если вы не используете какие-то уловки с $ PROMPT_COMMAND. Мне было интересно, есть ли способ запросить историю запущенного процесса bash. Меня не интересуют случаи, когда процесс порождается чем-то другим, кроме интерактивного bash, за исключением git, который сам был порожден из интерактивного bash.   -  person itsadok    schedule 12.07.2018
comment
Не то, чтобы я знаю, извините   -  person Aaron    schedule 12.07.2018
comment
А что если пользователь в crontab поместит? Вы не можете показать там сообщение пользователя. Разве вам не следует вместо этого добавить сообщение в / var / log / messages?   -  person Dominique    schedule 18.07.2018
comment
Вместо того, чтобы сжигать много циклов о том, как найти имя вызова (что, IMHO, есть много угловых случаев, когда он терпит неудачу) - Почему бы не поработать над сообщением для пользователей? Please add the --bar option to your command, like so: 'cmd --bar' Большинство людей достаточно умны (опять же, ИМХО), чтобы знать, что cmd является заменой того, что они набирали.   -  person dawg    schedule 18.07.2018
comment
Обратите внимание, что потенциально возможно заставить оболочку экспортировать копию BASH_COMMAND в среду из ловушки DEBUG, но если вы полагаетесь на это, ваша программа будет иметь под рукой поведение только при вызове из оболочка так подготовлена ​​... так что вряд ли это кажется полезным.   -  person Charles Duffy    schedule 19.07.2018
comment
@dawg это, конечно, текущее решение, которое у меня есть. Мне было интересно, есть ли способ сделать его более удобным.   -  person itsadok    schedule 19.07.2018
comment
Re: edits - если вы хотите пройтись по дереву процессов и посмотреть на командные строки родителей, пока не найдете команду git, да, вы можете это сделать. Псевдонимы Shell не встречаются нигде в истории, но поскольку вызов псевдонима git проходит через настоящую внешнюю команду, он появится.   -  person Charles Duffy    schedule 19.07.2018
comment
(Re: символические ссылки, для них работает стандартный argv[0] подход, опосредованный /proc/self/cmdline или иным образом).   -  person Charles Duffy    schedule 19.07.2018
comment
Кстати, полная командная строка в том виде, в котором она была набрана, - это тесно связанный вопрос .   -  person Charles Duffy    schedule 19.07.2018
comment
См. Мой обновленный ответ ниже: оберните сценарий python в сценарий bash, который предоставляет соответствующие сообщения об ошибках, например, на основе ненулевых кодов выхода.   -  person philwalk    schedule 19.07.2018


Ответы (5)


Нет, нет возможности увидеть исходный текст (до псевдонимов / функций / и т. Д.).

Запуск программы в UNIX выполняется следующим образом на базовом уровне системных вызовов:

int execve(const char *path, char *const argv[], char *const envp[]);

Примечательно, что есть три аргумента:

  • Путь к исполняемому файлу
  • Массив argv (первый элемент которого - argv[0] или $0 - передается этому исполняемому файлу, чтобы отразить имя, под которым он был запущен)
  • Список переменных среды

Здесь нет строки, которая предоставляет исходную введенную пользователем команду оболочки, из которой был запрошен вызов нового процесса. Это особенно верно, поскольку не все программы вообще запускаются из оболочки; рассмотрим случай, когда ваша программа запускается из другого скрипта Python с shell=False.


В UNIX совершенно обычным явлением считается, что ваша программа была запущена под любым именем, указанным в argv[0]; это работает для символических ссылок.

Вы даже можете увидеть, как это делают стандартные инструменты UNIX:

$ ls '*.txt'         # sample command to generate an error message; note "ls:" at the front
ls: *.txt: No such file or directory
$ (exec -a foobar ls '*.txt')   # again, but tell it that its name is "foobar"
foobar: *.txt: No such file or directory
$ alias somesuch=ls             # this **doesn't** happen with an alias
$ somesuch '*.txt'              # ...the program still sees its real name, not the alias!
ls: *.txt: No such file 

Если вы действительно хотите создать командную строку UNIX, используйте pipes.quote() (Python 2) или shlex.quote() (Python 3), чтобы сделать это безопасно.

try:
    from pipes import quote # Python 2
except ImportError:
    from shlex import quote # Python 3

cmd = ' '.join(quote(s) for s in open('/proc/self/cmdline', 'r').read().split('\0')[:-1])
print("We were called as: {}".format(cmd))

Опять же, псевдонимы не будут «разворачиваться», возвращаться к коду, который был вызван для вызова функции, вызвавшей вашу команду, и т. Д .; в этот колокол не перезвонить.


Это можно использовать для поиска экземпляра git в дереве родительских процессов и обнаружения его списка аргументов:

def find_cmdline(pid):
    return open('/proc/%d/cmdline' % (pid,), 'r').read().split('\0')[:-1]

def find_ppid(pid):
    stat_data = open('/proc/%d/stat' % (pid,), 'r').read()
    stat_data_sanitized = re.sub('[(]([^)]+)[)]', '_', stat_data)
    return int(stat_data_sanitized.split(' ')[3])

def all_parent_cmdlines(pid):
    while pid > 0:
        yield find_cmdline(pid)
        pid = find_ppid(pid)

def find_git_parent(pid):
    for cmdline in all_parent_cmdlines(pid):
        if cmdline[0] == 'git':
            return ' '.join(quote(s) for s in cmdline)
    return None
person Charles Duffy    schedule 18.07.2018
comment
@philwalk, если я правильно понимаю ваше предложение (получение истории из скрипта), оно чрезвычайно чувствительно к конфигурации времени выполнения - многие конфигурации оболочки вообще не будут записывать историю в файл до выхода. Если вы достаточно контролировали конфигурацию оболочки пользователя, чтобы убедиться, что она будет работать, вы можете просто попросить их установить DEBUG ловушку, которая экспортирует копию $BASH_COMMAND, и покончить с ней. - person Charles Duffy; 19.07.2018
comment
@philwalk, ... более того, совершенно неверно утверждать, что я предоставляю в качестве доказательства некоторые подходы, которые не работают - я предлагаю подход, который работает в случае псевдонима git (функция find_git_parent), и подход, который работает в случае символической ссылки (sys.argv[0], который, как я демонстрирую, является подходом, используемым стандартными инструментами UNIX). Это тот случай, когда разрешается решение, не зависящее от деталей конфигурации среды выполнения оболочки. - person Charles Duffy; 19.07.2018
comment
Я имел в виду заголовок вашего ответа. Нет возможности увидеть исходный текст (до псевдонимов / функций / и т. Д.). Мое решение именно так. - person philwalk; 20.07.2018
comment
@philwalk, а? Это не решение; OP хочет получить этот текст из интерпретатора Python. Вы можете получить его только из той же оболочки, которая выполнила команду - даже из подоболочки, интерпретирующей сценарий, без активного участия интерактивной родительской оболочки. - person Charles Duffy; 20.07.2018
comment
@philwalk, ... когда ваш aliasTest скрипт может достоверно определить, был ли if сам вызван через псевдоним, не требуя, чтобы оболочка, выполняющая этот вызов, заранее имела конфигурацию, отличную от стандартной, that < / b> когда я буду впечатлен - и не раньше. - person Charles Duffy; 20.07.2018
comment
в исходном вопросе конкретно спрашивалось, можно ли получить информацию из среды bash. И вопрос, сформулированный в настоящее время, требует способа настройки сообщений об ошибках, и мой ответ предоставляет необходимую информацию для этого. - person philwalk; 20.07.2018
comment
@philwalk, из среды bash, в Python (чтобы скрипт Python мог изменять свое сообщение об ошибке). - person Charles Duffy; 20.07.2018

См. Примечание внизу относительно первоначально предложенного сценария оболочки.

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

Например, если пользователь предпочитает вызывать скрипт Python 'myPyScript.py' через псевдоним, он может изменить определение псевдонима следующим образом:

  alias myAlias='myPyScript.py $@'

к этому:

  alias myAlias='myPyScript.py --caller=myAlias $@'

Если они предпочитают вызывать сценарий python из сценария оболочки, он может использовать дополнительную опцию командной строки, например:

  #!/bin/bash
  exec myPyScript.py "$@" --caller=${0##*/}

Другие возможные применения этого подхода:

  bash -c myPyScript.py --caller="bash -c myPyScript.py"

  myPyScript.py --caller=myPyScript.py

Для перечисления развернутых командных строк, вот сценарий 'pyTest.py', основанный на обратной связи @CharlesDuffy, который перечисляет cmdline для запущенного скрипта python, а также родительского процесса, который его породил. Если используется новый аргумент -caller, он появится в командной строке, хотя псевдонимы будут расширены и т. Д.

#!/usr/bin/env python

import os, re

with open ("/proc/self/stat", "r") as myfile:
  data = [x.strip() for x in str.split(myfile.readlines()[0],' ')]

pid = data[0]
ppid = data[3]

def commandLine(pid):
  with open ("/proc/"+pid+"/cmdline", "r") as myfile:
    return [x.strip() for x in str.split(myfile.readlines()[0],'\x00')][0:-1]

pid_cmdline = commandLine(pid)
ppid_cmdline = commandLine(ppid)

print "%r" % pid_cmdline
print "%r" % ppid_cmdline

После сохранения в файл с именем 'pytest.py' и последующего вызова его из сценария bash с именем 'pytest.sh' с различными аргументами, вот результат:

$ ./pytest.sh a b "c d" e
['python', './pytest.py']
['/bin/bash', './pytest.sh', 'a', 'b', 'c d', 'e']

ПРИМЕЧАНИЕ: критика оригинального сценария оболочки aliasTest.sh была верной. Хотя наличие заранее определенного псевдонима является частью спецификации вопроса и может предполагаться, что оно существует в пользовательской среде, предложение определило псевдоним (создавая вводящее в заблуждение впечатление, что это часть рекомендации, а не указанная часть среды пользователя), и не было показано, как оболочка будет взаимодействовать с вызываемым скриптом python. На практике пользователь должен либо создать оболочку, либо определить псевдоним внутри оболочки, а сценарий python должен будет делегировать печать сообщений об ошибках нескольким настраиваемым сценариям вызова (где находится информация о вызове), а клиенты будут иметь для вызова сценариев оболочки. Решение этих проблем привело к более простому подходу, который можно расширить до любого количества дополнительных вариантов использования.

Вот менее запутанная версия исходного сценария для справки:

#!/bin/bash
shopt -s expand_aliases
alias myAlias='myPyScript.py'

# called like this:
set -o history
myAlias $@
_EXITCODE=$?
CALL_HISTORY=( `history` )
_CALLING_MODE=${CALL_HISTORY[1]}

case "$_EXITCODE" in
0) # no error message required
  ;;
1)
  echo "customized error message #1 [$_CALLING_MODE]" 1>&2
  ;;
2)
  echo "customized error message #2 [$_CALLING_MODE]" 1>&2
  ;;
esac

Вот результат:

$ aliasTest.sh 1 2 3
['./myPyScript.py', '1', '2', '3']
customized error message #2 [myAlias]
person philwalk    schedule 18.07.2018
comment
Я работаю над версией, в которой учтены ваши отзывы, спасибо! - person philwalk; 19.07.2018
comment
Имейте в виду, что история не всегда сохраняется вообще - если команда запускается с предшествующим пробелом, например, она даже не сохраняется в истории в памяти, а тем более сбрасывается на диск с HISTCONTROL установлен на nospace или ignoreboth. И даже когда он хранится, сброс после каждой команды должен быть включен явно. А поскольку разные оболочки имеют разную историю, этот подход должен знать, какую из них использует пользователь, чтобы хотя бы иметь шанс. - person Charles Duffy; 19.07.2018
comment
Я был очень взволнован идеей обернуть скрипт python скриптом bash, но обнаружил, что скрипт bash не видит историю своего родителя, если я не заставлю пользователей всегда его использовать, что я не считаю жизнеспособным вариантом . Похоже, предложение Чарльза Даффи об использовании DEBUG является наиболее многообещающим. - person itsadok; 22.07.2018
comment
@itsadok ... в приведенном выше примере aliasTest.sh он создает точную командную строку, вызываемую из сценария bash, без необходимости использования каких-либо сценариев. - person philwalk; 23.07.2018
comment
Очень простой альтернативой, если вы можете указать псевдоним или документ, как он должен быть создан, является передача псевдонима или сценария аргумента, идентифицирующего требуемый тег для сообщения об ошибке. Или, что то же самое, если псевдоним создается для сценария оболочки с именем fooForAlias.sh, вы можете идентифицировать его в sys.argv [0], предоставляя желаемую информацию. - person philwalk; 24.07.2018
comment
@philwalk работает в aliasTest.sh, потому что вы используете команду history из того же процесса bash, который вызвал эти команды. Невозможно узнать, как был вызван сам сценарий aliasTest.sh. - person itsadok; 24.07.2018
comment
@philwalk, ... это означает, что если ваша программа хочет иметь такую ​​обработку ошибок при вызове из оболочки пользователя, вам необходимо, чтобы код выполнялся history в самой оболочке пользователя, а не в скрипт, запускаемый оболочкой. Это не подход, которому можно было бы разумно следовать на практике, равно как и хорошая гигиена - если бы каждая программа выводила только хорошие сообщения об ошибках для пользователей, которые изменяют свою конфигурацию оболочки, чтобы обернуть ее вызов, у нас был бы беспорядок. - person Charles Duffy; 25.07.2018
comment
@Charles Duffy ... Мне придется обновить описание, поскольку очевидно неясно, что я предлагаю ... клиенты должны вызывать через сценарий оболочки, а не имитировать, как он вызывает сценарий python. Для каждого варианта использования требуется отдельная оболочка. - person philwalk; 26.07.2018
comment
Я не понимаю, как вызов через оболочку решает проблему - оболочка не имеет доступа к истории своего родительского процесса, только к своей собственной истории, если оболочка пользователя не имеет очень специфической конфигурации ( немедленно сбрасывать историю на диск при каждой команде, что не поведения по умолчанию). Но да, пожалуйста, отредактируйте, чтобы продемонстрировать. - person Charles Duffy; 26.07.2018
comment
Кроме того: $@ бесполезен внутри псевдонима - псевдонимы - это просто подстановка префикса, поэтому весь оставшийся текст всегда следует за ними. Таким образом, alias foo='bar "$@"', а затем foo one two three вызывает bar "$@" one two three; вы не замечаете этого в типичных сценариях, потому что для интерактивной оболочки $@ почти всегда является списком без элементов (если вы не изо всех сил изменили его, как с set -- "first argument" "second argument"). - person Charles Duffy; 27.07.2018
comment
(А без кавычек $@ идентичен $*, то есть отбрасывает разницу между "first argument" "second argument" и "first" "argument" "second" "argument"). - person Charles Duffy; 27.07.2018
comment
... вернемся к делу: если вы собирались изменить вызывающую оболочку, вы могли бы просто изменить ее, установив $0, и, таким образом, совсем не нуждаться в дополнительном аргументе командной строки. Например: myAlias() { exec -a myAlias myPyScript "$@"; } вызовет myPyScript с myAlias в $0. - person Charles Duffy; 27.07.2018

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

Доказательство:

$ cat test.sh 
#!/usr/bin/env bash

ps -o command $$

$ bash ./test.sh 
COMMAND
bash ./test.sh

$ ./test.sh 
COMMAND
bash ./test.sh

Это мешает вам обнаружить разницу между первыми двумя случаями в вашем списке.

Я также уверен, что не существует разумного способа идентифицировать другие (опосредованные) способы вызова команды.

person Leon    schedule 18.07.2018
comment
Я согласен с тем, что невозможно надежно получить исходную командную строку оболочки, но я не согласен с тем, что вы доказали это здесь. Данные в /proc/self значительно лучше, чем в ps. cmdline_for_pid() { local -a args; local arg; args=( ); while IFS= read -r -d '' arg; do args+=( "$arg" ); done </proc/"$1"/cmdline; printf '%q ' "${args[@]}"; echo; }, например, определяет cmdline_for_pid функцию, которая обеспечивает значительно лучший листинг, чем ps. - person Charles Duffy; 19.07.2018
comment
@CharlesDuffy Для моего тестового примера cmdline_for_pid не отличается от ps -o command - person Leon; 19.07.2018
comment
используйте более интересный тестовый пример - с пробелами, кавычками и т. д. - person Charles Duffy; 19.07.2018
comment
@CharlesDuffy Я знаю разницу. Я просто хотел отметить, что для иллюстрации моего утверждения cmdline_for_pid не добавляет ничего полезного, требуя от читателя расшифровать доказательство. - person Leon; 19.07.2018
comment
Тогда я понял, что слово «доказательство» означает нечто иное, чем то, что вы имели в виду. Насколько я это читаю, только доказано, какие данные доступны, а какие нет, если эти данные отражены в полной и канонической форме; перевод с потерями не доказывает ничего полезного в отношении того, что могло быть извлечено с помощью процесса с меньшими потерями, и, таким образом, не доказывает ничего о том, какие данные фактически доступны для извлечения, а какие нет. - person Charles Duffy; 19.07.2018

Я вижу два способа сделать это:

  • Самым простым, как предлагает 3sky, было бы проанализировать командную строку изнутри скрипта python. Для этого можно надежно использовать argparse. Это работает, только если вы можете изменить этот сценарий.
  • Более сложный, более общий и сложный способ - изменить python исполняемый файл в вашей системе.

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

Независимо от того, как вызывается ваш скрипт, запускается python. Здесь цель состоит в том, чтобы заменить исполняемый файл python скриптом, который проверяет, входит ли foo.py в число аргументов, и если это так, то проверяет, есть ли --bar. Если нет, распечатайте сообщение и вернитесь.

В любом другом случае запустите настоящий исполняемый файл python.

Теперь, надеюсь, запуск python выполняется с помощью следующего шебанга: #!/usr/bin/env python3 или python foo.py, а не варианта #!/usr/bin/python или /usr/bin/python foo.py. Таким образом, вы можете изменить переменную $PATH и добавить каталог, в котором находится ваш ложный python.

В противном случае вы можете заменить /usr/bin/python executable, рискуя не сыграть с обновлениями.

Более сложный способ сделать это, вероятно, будет с пространствами имен и монтировками, но вышеизложенного, вероятно, достаточно, особенно если у вас есть права администратора.


Пример того, что может работать как скрипт:

#!/usr/bin/env bash

function checkbar
{
    for i in "$@"
    do
            if [ "$i" = "--bar" ]
            then
                    echo "Well done, you added --bar!"
                    return 0
            fi
    done
    return 1
}

command=$(basename ${1:-none})
if [ $command = "foo.py" ]
then
    if ! checkbar "$@"
    then
        echo "Please add --bar to the command line, like so:"
        printf "%q " $0
        printf "%q " "$@"
        printf -- "--bar\n"
        exit 1
    fi
fi
/path/to/real/python "$@"

Однако, перечитав ваш вопрос, становится очевидно, что я его неправильно понял. На мой взгляд, можно просто напечатать либо «foo.py должен вызываться как foo.py --bar», «пожалуйста, добавьте панель к своим аргументам» или «пожалуйста, попробуйте (вместо)», независимо от того, что пользователь ввел:

  • Если это псевдоним (git), это однократная ошибка, и пользователь попробует использовать свой псевдоним после его создания, чтобы знать, куда поместить часть --bar.
  • with either with /usr/bin/foo.py or python foo.py:
    • If the user is not really command line-savvy, they can just paste the working command that is displayed, even if they don't know the difference
    • Если это так, они должны быть в состоянии без проблем понять сообщение и настроить свою командную строку.
person MayeulC    schedule 18.07.2018
comment
"$@", а не $@. Без кавычек $@ ведет себя так же, как и без кавычек $* - это означает, что все ваши аргументы разделяются на строки и раскрываются как глобусы. - person Charles Duffy; 19.07.2018
comment
И exit -1 не имеет смысла - статус выхода UNIX - это однобайтовое беззнаковое (положительное) целое число. И [ не обещает, что == вообще будет работать - единственный POSIX- стандартизированный оператор сравнения строк - =. И x бесполезен / бесполезен, когда вы цитируете свои расширения и не используете test режимы, помеченные как устаревшие (-a и -o вводят синтаксические двусмысленности, но их здесь нет). - person Charles Duffy; 19.07.2018
comment
Да, это было быстро собрано в качестве примера и не было тщательно проверено; Я хотел быть в безопасности с x. Вы правы, я поменяю оба $@ на "$@". Бит знака делает возвращаемое значение 255, но я могу изменить его на 1, так как на самом деле это не имеет большого значения. Однако этот ответ на самом деле не по теме, поскольку он не отвечает на опасения OP. - person MayeulC; 19.07.2018

Я знаю, что это bash задача, но я думаю, что самый простой способ - изменить 'foo.py'. Конечно, это зависит от уровня сложности скрипта, но, возможно, подойдет. Вот пример кода:

#!/usr/bin/python

import sys

if len(sys.argv) > 1 and sys.argv[1] == '--bar':
    print 'make magic'
else:
    print 'Please add the --bar option to your command, like so:'
    print '    python foo.py --bar'

В этом случае не имеет значения, как пользователь запускает этот код.

$ ./a.py
Please add the --bar option to your command, like so:
    python foo.py --bar

$ ./a.py -dua
Please add the --bar option to your command, like so:
    python foo.py --bar

$ ./a.py --bar
make magic

$ python a.py --t
Please add the --bar option to your command, like so:
    python foo.py --bar

$ /home/3sky/test/a.py
Please add the --bar option to your command, like so:
    python foo.py --bar

$ alias a='python a.py'
$ a
Please add the --bar option to your command, like so:
    python foo.py --bar

$ a --bar
make magic
person 3sky    schedule 18.07.2018
comment
Ваш ответ никак не отвечает на вопрос ОП. Ваше решение всегда выдает одно и то же сообщение, если опция --bar не указана, тогда как OP требует другого сообщения в зависимости от фактически используемой команды. - person Leon; 18.07.2018