its*_*dok 14 linux bash command-line-interface
这是问题所在:我有这个脚本foo.py,如果用户在没有--bar选项的情况下调用它,我想显示以下错误消息:
Please add the --bar option to your command, like so:
python foo.py --bar
Run Code Online (Sandbox Code Playgroud)
现在,棘手的部分是用户可能有多种方式调用该命令:
python foo.py在示例中使用过/usr/bin/foo.pyfrob='python foo.py',并且实际上已经运行了frobflab=!/usr/bin/foo.py,他们使用了git flab在每种情况下,我都希望消息反映用户如何调用命令,这样我提供的示例才有意义.
sys.argv总是包含foo.py,/proc/$$/cmdline不知道别名.在我看来,这个信息的唯一可能来源是bash本身,但我不知道如何问它.
有任何想法吗?
更新如果我们将可能的情况限制为仅限于上面列出的情况怎么样?
更新2:很多人写了很好的解释为什么在一般情况下这是不可能的,所以我想限制我的问题:
根据以下假设:
foo <args> 其中foo是符号链接/ usr/bin/foo - > foo.pygit foo 其中alias.foo =!/ usr/bin/foo in ~/.gitconfiggit baz 其中alias.baz =!/ usr/bin/foo in ~/.gitconfig有没有办法区分脚本中的1和(2,3)?有没有办法区分脚本中的2和3?
我知道这是一个很长的镜头,所以我现在接受了Charles Duffy的回答.
更新3:到目前为止,Charles Duffy在下面的评论中提出了最有希望的角度.如果我可以让我的用户拥有
trap 'export LAST_BASH_COMMAND=$(history 1)' DEBUG
Run Code Online (Sandbox Code Playgroud)
在他们的.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.")
Run Code Online (Sandbox Code Playgroud)
这样,如果我不设法获取它们的调用方法,我会显示一般消息.当然,如果我要依赖于改变用户的环境,我也可以确保各种别名导出我自己可以看到的环境变量,但至少这种方式允许我对任何用户使用相同的技术.我可能稍后添加的其他脚本.
Cha*_*ffy 16
在UNIX中启动程序在底层系统调用级别完成如下:
int execve(const char *path, char *const argv[], char *const envp[]);
Run Code Online (Sandbox Code Playgroud)
值得注意的是,有三个论点:
argv[0]或$0- 传递给该可执行文件以反映启动它的名称)这里没有任何地方提供原始用户输入的shell命令,从该命令请求新进程的调用.这尤其正确,因为并非所有程序都是从shell启动的 ; 考虑从另一个Python脚本启动程序的情况shell=False.
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
Run Code Online (Sandbox Code Playgroud)
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))
Run Code Online (Sandbox Code Playgroud)
同样,这不会"取消扩展"别名,恢复为调用调用调用命令的函数的代码等; 钟声没有响.
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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
397 次 |
| 最近记录: |