21

I use Bash as my interactive shell and I was wondering if there was an easy way to get Bash to run a system command instead of a shell builtin command in the case where they both share the same name.

For example, use the system kill (from util-linux) to print the process id (pid) of the named process(es) instead of sending a signal:

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

Without specifying the full path of the system command, the Bash builtin is used instead of the system command. The kill builtin doesn’t have the -p option so the command fails:

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

I tried the answers listed in Make bash use external `time` command rather than shell built-in but most of them only work because time is actually a shell keyword – not a shell builtin.

Other than temporarily disabling the Bash builtin with enable -n kill, the best solution I’ve seen so far is to use:

$(which kill) -p httpd

Are there other easier (involve less typing) ways to execute an external command instead of a shell builtin?

Note that kill is just an example and I’d like a generalised solution similar to the way that prefixing with the command builtin prevents functions which have the same name as an external command from being run. In most cases, I usually prefer to use the builtin version as it saves forking a new process and some times the builtin has features that the external command doesn’t.

3
  • Enclosing which kill in backticks (can't put them in comments) is slightly shorter.
    – abligh
    Commented Nov 12, 2015 at 14:15
  • @abligh Good point. I've spent years training myself to use the "new"er syntax for command substitution.:) Commented Nov 12, 2015 at 14:37
  • @abligh: FYI, you can put `backticks` into comments by preceding them with backslashes (\).  But there are reasons to stick with $(…) — see this, this, and this. Commented Apr 19, 2016 at 20:56

6 Answers 6

25

Assuming env is in your path:

env kill -p http

env runs the executable file named by its first argument in a (possibly) modified environment; as such, it does not know about or work with shell built-in commands.

This produces some shell job control cruft, but doesn't rely on an external command:

exec kill -p bash &

exec requires an executable to replace the current shell, so doesn't use any built-ins. The job is run in the background so that you replace the forked background shell, not your current shell.

4
  • 2
    env is clearly the right answer IMHO.
    – abligh
    Commented Nov 12, 2015 at 14:38
  • @abligh: You're right in comment in my deleted answer. command -p cmd calling external command in zsh, not bash.
    – cuonglm
    Commented Nov 12, 2015 at 15:39
  • 8
    (exec kill -p http) causes the job to replace a sub-shell instead of your current shell and you don't have to deal with the job control cruft. Commented Nov 12, 2015 at 23:44
  • 1
    @AnthonyGeoghegan Indeed, but env also doesn't know about shell builtins, since it's not a shell. You'd get the same effect with nice or xargs or any other program like that. Commented Nov 13, 2015 at 0:05
1

The simplest way to do what you want might be to put the line

alias kill="/bin/kill"

into your ~/.bashrc file. After that, each new login/invocation of bash will interpret "kill" as /bin/kill.

1
  • I had already thought of an alias and that was one of the solutions listed in the question I linked to but I’m hoping for a more generalised solution (similar to the command solution) rather than create a separate alias for each “shadowed” command. I’ve now edited my question to make this clearer and more explicit. In most cases, I usually prefer to use the builtin version as processes can be specified by job IDs. Thanks, anyway. Commented Nov 12, 2015 at 13:26
1

If you know a solution that requires some typing and you want a solution that requries less typing, build it:

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

Abbreviating stuff that normally takes some effort is what computers excel at.

1
  • 1
    That's a good general point so I'll upvote your answer. Over the past few years, I've built up a collection of aliases, functions and scripts for the systems that I regularly use. However, I prefer to use non-customised solutions where possible as I sometimes have to work on fresh installs or servers that I didn't set up. Thanks. Commented Nov 12, 2015 at 20:34
1

In this very specific case, the command pgrep is an exact match for the need.

In a general sense, a function works. From "file command":

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

call as

fcmd kill -p httpd

But if you need less typing, there is no shorter way than a good alias.

From the concept "list pid" (lp):

alias lp='/bin/kill -p'

then, just type:

lp httpd
0

(In zsh) You can prefix any command name with an = sign to get the system version instead of a builtin. This is also a handy way to dodge any aliases that mess up a specific scenario.

$ =kill -p httpd
3
  • 1
    I tried that with Bash version 4.3.30 and it didn't work. I've never seen such syntax before; can you add a link to where this feature is documented? I'd normally prefix an alias with a backslash to run the non-aliased version of a command. Commented Nov 12, 2015 at 20:28
  • @Anthony maybe this is a zsh only thing. I use it regularly but I'll check on bash from a computer tomorrow.
    – Caleb
    Commented Nov 12, 2015 at 20:31
  • I suspected it might be some shell that I'm not familiar with (I’m only familiar with bash, dash and csh). There was another answer (since deleted) that only worked for zsh. While I tagged this question with bash and used it in the title, you should keep this answer as a zsh user would still find it useful. Commented Nov 12, 2015 at 20:41
-2

You could send a bugreport against your kill manpage and ask why this includes non-standard options that are taken from pkill and use pkill whenever you like to get the features from pkill.

If you call:

pkill httpd

you avoid the problems you describe.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .