使用系统命令而不是内置的Bash而不指定完整路径


17

我使用Bash作为我的交互式外壳,我想知道是否有一种简单的方法可以使Bash在共享相同名称的情况下运行系统命令而不是外壳内置命令。

例如,使用系统kill(from util-linux)打印指定进程的进程ID(pid),而不发送信号:

$ /bin/kill -p httpd
2617
...

在不指定系统命令的完整路径的情况下,将使用Bash内置函数代替系统命令。该kill内建不具备-p这样的命令失败选项:

$ kill -p httpd
bash: kill: p: invalid signal specification

我尝试了使bash使用外部`time`命令而不是内置的shell列出的答案但是它们中的大多数只能使用,因为time实际上是一个shell 关键字 –而不是内置的shell

除了暂时禁用内置的Bash之外enable -n kill,到目前为止,我所看到的最佳解决方案是使用:

$(which kill) -p httpd

是否有其他更简单的方式(较少的输入操作)来执行外部命令而不是内置的Shell?

请注意,这kill只是一个示例,我想要一个通用的解决方案,类似于使用command内置前缀防止运行与外部命令同名的函数的方式。在大多数情况下,我通常更喜欢使用内置版本,因为它节省了创建新进程的时间,并且有时内置功能具有外部命令所没有的功能。


封闭which kill在反引号(不能把他们在评论)是短。
2015年

@abligh好点。我花了几年时间训练自己使用的“新”呃语法命令替换:)
安东尼摹-正义莫妮卡

@abligh:仅供参考,您可以在反引号前面加上反斜杠(\),以将反引号放入注释中。但是,我们有理由坚持下去$(…)-看到这个这个这个
G-Man说'恢复莫妮卡'

Answers:


20

假设env您的路径是:

env kill -p http

env在(可能)已修改的环境中运行以其第一个参数命名的可执行文件;因此,它不了解或无法使用Shell内置命令。

这会产生一些shell作业控制问题,但不依赖外部命令:

exec kill -p bash &

exec需要一个可执行文件来替换当前的shell,因此不使用任何内置程序。该作业在后台运行,因此您可以替换派生的后台shell,而不是当前的shell。


2
env显然是恕我直言的正确答案。
2015年

@abligh:您在我删除的答案中的评论中是正确的。command -p cmd调用外部命令zsh,不是bash
cuonglm 2015年

6
(exec kill -p http)导致作业替换了子外壳而不是当前的外壳,因此您不必处理作业控制问题。
Michael Hoffman 2015年

1
@AnthonyGeoghegan的确,但是env也不知道shell内置的东西,因为它不是shell。使用nicexargs或类似的任何其他程序,您将获得相同的效果。
user253751

1

做你想做的最简单的方法可能就是把线

alias kill="/bin/kill"

到您的~/.bashrc文件中。之后,每次bash的每次新登录/调用都将“ kill”解释为/bin/kill


我已经想到了别名,这是我链接到的问题中列出的解决方案之一,但是我希望有一个更通用的解决方案(类似于该command解决方案),而不是为每个“影子”命令创建一个单独的别名。我现在已经编辑了我的问题,以使这一点更加清楚和明确。在大多数情况下,我通常更喜欢使用内置版本,因为可以通过作业ID指定进程。不管怎么说,还是要谢谢你。
安东尼G-莫妮卡的大法官,2015年

1

如果您知道需要某种输入的解决方案,并且想要一种需要较少输入的解决方案,请构建它:

runFile() { local cmd="$1"; shift; cmd="$(which "$cmd")" && "$cmd" "$@"; }

计算机通常擅长简化一些通常需要花费精力的工作。


1
这是一个很好的一般观点,因此我会支持您的回答。在过去的几年中,我为我经常使用的系统建立了别名,函数和脚本的集合。但是,我倾向于尽可能使用非定制的解决方案,因为有时我不得不在未安装的全新安装或服务器上工作。谢谢。
安东尼G-莫妮卡的大法官,2015年

1

在这种非常特殊的情况下,命令 pgrep与需要完全匹配。

在一般意义上,功能是可行的。从“文件命令”:

fcmd(){ local a=$1; shift; $(which "$a") "$@"; }

称为

fcmd kill -p httpd

但是,如果您需要更少的输入,没有比别名更好的方法了。

从概念“列表pid”(lp):

alias lp='/bin/kill -p'

然后,只需键入:

lp httpd

0

(在zsh中)您可以在任何命令名称前添加=符号,以获取系统版本而不是内置版本。这也是避免任何混淆特定场景的别名的简便方法。

$ =kill -p httpd

1
我在Bash 4.3.30版本中尝试过,但是没有用。我以前从未见过这样的语法;您可以在此功能的文档添加链接吗?我通常会给别名加上反斜杠前缀,以运行命令的非别名版本。
安东尼·G-莫妮卡的正义

@Anthony也许这是zsh唯一的事情。我会定期使用它,但是bash明天我将通过计算机进行检查。
Caleb 2015年

我怀疑这可能是一些我不熟悉的外壳(我只熟悉bash,dash和csh)。还有另一个答案(已删除)(仅适用于)zsh。当我用这个问题标记bash并在标题中使用它时,您应该保留此答案,因为zsh用户仍然会发现它很有用。
安东尼·G-莫妮卡的正义

-1

您可以在kill联机帮助页上发送错误报告,并询问为什么其中包括从中获取pkill和使用的非标准选项,pkill只要您希望从中获取功能pkill.

如果您致电:

pkill httpd

您可以避免描述的问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.