There was an interesting discussion on the opensuse mailing list about finding out which command is going to get used when you type something in. The Original Poster (OP) couldn't figure out why some options found in the time
man page weren't working:
$ time -o ls
bash: -o: command not found
real 0m0.008s
user 0m0.000s
sys 0m0.000s
$ time --help
bash: --help: command not found
real 0m0.003s
user 0m0.000s
sys 0m0.008s
$
Of course, any veteran of the commandline could tell you it is not executing the time
command as documented in the man page, but some other time
command, in this case bash's builtin time
command, which doesn't have the -o or the --help options. So you have to tell the shell exactly which command you are looking to execute, or use bash's man page or help
command to get info on its version:
$ /usr/bin/time -o t.out ls
$ /usr/bin/time --help
Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]
[--portability] [--format=format] [--output=file] [--version]
[--help] command [arg...]
$ help time
time: time [-p] PIPELINE
Execute PIPELINE and print a summary of the real time, user CPU time,
and system CPU time spent executing PIPELINE when it terminates.
The return status is the return status of PIPELINE. The `-p' option
prints the timing summary in a slightly different format. This uses
the value of the TIMEFORMAT variable as the output format.
times: times
Print the accumulated user and system times for processes run from
the shell.
So the discussion evolved into answering the important question - "How can you tell which command is actually getting executed when you don't type in the full path?" One hint is in the question - use the which
command:
$ which time
/usr/bin/time
$ which -a time
/usr/bin/time
$
Hmm, now that doesn't work! That's what I had always used, especially the -a flag, which should show all versions of the command, rather than just the first one. It turns out a better option is bash's builtin type
command, which does know about aliases and builtins:
$ type time
time is a shell keyword
$ type -a time
time is a shell keyword
time is /usr/bin/time
$
Okay, that's much better, although the suggestion to use the -p option just makes it revert back to the mysteriously incomplete which
output:
$ type -ap time
/usr/bin/time
$ help type
type: type [-afptP] name [name ...]
For each NAME, indicate how it would be interpreted if used as a
command name.
If the -t option is used, `type' outputs a single word which is one of
`alias', `keyword', `function', `builtin', `file' or `', if NAME is an
alias, shell reserved word, shell function, shell builtin, disk file,
or unfound, respectively.
If the -p flag is used, `type' either returns the name of the disk
file that would be executed, or nothing if `type -t NAME' would not
return `file'.
If the -a flag is used, `type' displays all of the places that contain
an executable named `file'. This includes aliases, builtins, and
functions, if and only if the -p flag is not also used.
The -f flag suppresses shell function lookup.
The -P flag forces a PATH search for each NAME, even if it is an alias,
builtin, or function, and returns the name of the disk file that would
be executed.
typeset: typeset [-afFirtx] [-p] name[=value] ...
Obsolete. See `declare'.
So I learned about the type
command, which is really what you want to use. But then I started investigating the which
command, which led to a surprise:
$ type -a which
which is aliased to `_which'
which is /usr/bin/which
$ type -a _which
_which is a function
_which ()
{
local file=$(type -p ${1+"$@"} 2>/dev/null);
if test -n "$file" -a -x "$file"; then
echo "$file";
return 0;
fi;
hash -r;
type -P ${1+"$@"}
}
Whoa, where did that come from? A quick perusal of the bash man page tells me bash, on start up:
When bash is invoked as an interactive login shell, or as a non-interactive shell
with the --login option, it first reads and executes commands from the file /etc/pro-
file, if that file exists. After reading that file, it looks for ~/.bash_profile,
~/.bash_login, and ~/.profile, in that order, and reads and executes commands from
the first one that exists and is readable. The --noprofile option may be used when
the shell is started to inhibit this behavior.
So I checked out /etc/profile, which is a very long shell script doing all kinds of interesting things, worth a post all in its own. But one of the last things it does is to execute /etc/bash.bashrc, which again is a fascinating script setting a whole bunch of mostly bash-specific things, again worth a look at in itself. In there, a whole bunch of aliases get set up and there is this section:
if test "$is" = "bash" ; then
#
# Other shells use the which command in path (e.g. ash) or
# their own builtin for the which command (e.g. ksh and zsh).
#
_which () {
local file=$(type -p ${1+"$@"} 2>/dev/null)
if test -n "$file" -a -x "$file"; then
echo "$file"
return 0
fi
hash -r
type -P ${1+"$@"}
}
alias which=_which
fi
Interesting. I wonder why they do this instead of using the /usr/bin/which
command in the path? It doesn't seem to improve anything over the system which
command except add an unnecessary layer of obfuscation.
But I will look over my .bashrc file, which, much like my .emacs file, has accompanied me for many years, to see what I should remove as redundant, as the openSUSE standard one does a lot of it already. I wonder how standard it is on other Linux distros? Looks like I'll have to check the MACHTYPE environment variable for the Linux type:
jdarnold@opensuse $ echo $MACHTYPE
i686-suse-linux
$
jarnold@redhat $ echo $MACHTYPE
i386-redhat-linux-gnu
$
No comments:
Post a Comment