- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
问题是:我有这个脚本 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
flab=!/usr/bin/foo.py
, 他们使用了 git flab
在任何情况下,我都希望消息反射(reflect)用户如何调用命令,这样我提供的示例才有意义。
sys.argv
始终包含 foo.py
, 和 /proc/$$/cmdline
不知道别名。在我看来,此信息的唯一可能来源是 bash 本身,但我不知道如何询问它。
有什么想法吗?
更新 如果我们将可能的情况限制为仅上面列出的情况怎么样?
更新 2:很多人写了很好的解释,说明为什么这在一般情况下是不可能的,所以我想把我的问题限制在这个方面:
在以下假设下:
foo <args>
其中 foo 是符号链接(symbolic link)/usr/bin/foo -> foo.pygit foo
其中 alias.foo=!/usr/bin/foo 在 ~/.gitconfig
中git baz
其中 alias.baz=!/usr/bin/foo 在 ~/.gitconfig
中有没有办法从脚本中区分 1 和 (2,3)?有没有办法从脚本中区分 2 和 3?
我知道这是不可能的,所以我现在接受 Charles Duffy 的回答。
更新 3:到目前为止,Charles Duffy 在下面的评论中提出了最有希望的角度。如果我能让我的用户拥有
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.")
这样,如果我无法获取他们的调用方法,我会显示一般消息。当然,如果我要依靠改变我的用户环境,我也可以确保各种别名导出它们自己的环境变量,我可以查看,但至少这种方式允许我对任何应用程序使用相同的技术我稍后可能会添加其他脚本。
最佳答案
在 UNIX 中启动程序是在底层系统调用级别按如下方式完成的:
int execve(const char *path, char *const argv[], char *const envp[]);
值得注意的是,存在三个参数:
argv[0]
或 $0
-- 被传递给该可执行文件以反射(reflect)其启动时的名称)这里没有一个字符串提供原始用户输入的 shell 命令,从中请求新进程的调用。 尤其如此,因为并非所有程序都是从 shell 启动的;考虑一下您的程序是从另一个具有 shell=False
的 Python 脚本启动的情况。
argv[0]
中给出的任何名称启动的,这是完全常规的;这适用于符号链接(symbolic link)。您甚至可以看到标准的 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
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))
同样,这不会“取消扩展”别名,恢复到被调用以调用调用您的命令的函数的代码,等等;没有响铃。
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
关于linux - 有没有办法知道用户如何从 bash 调用程序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51301508/
我是一名优秀的程序员,十分优秀!