bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: test for "command not found" before expanding shell parameters


From: Eduardo A . Bustamante López
Subject: Re: test for "command not found" before expanding shell parameters
Date: Sun, 20 Apr 2014 13:26:52 -0700
User-agent: Mutt/1.5.21 (2010-09-15)

On Sun, Apr 20, 2014 at 08:05:08PM +0200, Toralf Förster wrote:
> If "greo" does not exist - will bash in that case expand /var/db/pkg/*/*/USE 
> neverttheless ?
I understand that you want this for *interactive* stuff. Storing the
command in a variable and then test with 'command -v' surely is too
much hassle for this to be practical. If you're going to put the name
in a variable, then test if the command exists, and then run the
command, I find it easier to not make typos on the first place ;)

But well, regarding your original question, I wrote this:

tl;dr: Your request would break the standard, but you can use the
DEBUG trap to inspect $BASH_COMMAND and see if there's a valid
command name there.

It is mandated by POSIX that Pathname expansion occurs before the
shell determines if a word corresponds to a command name.

Read here:
<http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01>

It says:

| 2.9.1 Simple Commands
| 
| A "simple command" is a sequence of optional variable assignments and
| redirections, in any sequence, optionally followed by words and redirections,
| terminated by a control operator.
| 
| When a given simple command is required to be executed (that is, when any
| conditional construct such as an AND-OR list or a case statement has not
| bypassed the simple command), the following expansions, assignments, and
| redirections shall all be performed from the beginning of the command text to
| the end:
| 
| 1. The words that are recognized as variable assignments or redirections
| according to Shell Grammar Rules are saved for processing in steps 3 and 4.
| 
| 2. The words that are not variable assignments or redirections shall be
| expanded. If any fields remain following their expansion, the first field
| shall be considered the command name and remaining fields are the arguments
| for the command.
| 
| 3. Redirections shall be performed as described in Redirection.
| 
| 4. Each variable assignment shall be expanded for tilde expansion, parameter
| expansion, command substitution, arithmetic expansion, and quote removal
| prior to assigning the value.
| 
| In the preceding list, the order of steps 3 and 4 may be reversed if no
| command name results from step 2 or if the command name matches the name of a
| special built-in utility; see Special Built-In Utilities.

If you modify 2 to fit your request:

- Break POSIX compatibility (which is OK if the option can be set via
  shopt)
- It'll have to take Pathname expansion as a special case, because
  I've seen many scripts depending on other expansions performed in
  step two, for example, scripts that store command lines in
  variables.


Also, you don't have to patch bash to achieve this. You can use the
DEBUG trap. This approach must have some problems though, but it
should be enough for a pratical use: 

| dualbus@debian:~/y$ shopt -s extglob extdebug
| dualbus@debian:~/y$ cat ~/trap 
| trap '(
| get_command() {
|   local p="+([!=])=*([!=])[[:space:]]";
| 
|   if [[ $1 = $p* ]]; then
|     get_command "${1#$p}";
|   else
|     printf %s "$1";
|   fi;
| };
| command=$(get_command "$BASH_COMMAND");
| command=${command%%[[:space:]]*}
| if type -t "$command"  >/dev/null 2>&1; then
|   exit 0
| else
|   printf \
|     "DEBUG: command not found: %s\n" \
|     "$command"
|   exit 1
| fi
| )' DEBUG
| dualbus@debian:~/y$ . ~/trap 
| dualbus@debian:~/y$ ls
| dualbus@debian:~/y$ lsa
| DEBUG: command not found: lsa
| dualbus@debian:~/y$ time lsa
| DEBUG: command not found: lsa
| 
| real  0m0.003s
| user  0m0.004s
| sys 0m0.000s
| dualbus@debian:~/y$ time lsa $(sleep 10000)
| DEBUG: command not found: lsa
| 
| real  0m0.002s
| user  0m0.000s
| sys 0m0.000s
| dualbus@debian:~/y$ time lsa $(sleep 5)
| DEBUG: command not found: lsa
| 
| real  0m0.002s
| user  0m0.000s
| sys 0m0.000s
| dualbus@debian:~/y$ time ls $(sleep 5)
| 
| real  0m5.005s
| user  0m0.000s
| sys 0m0.000s




reply via email to

[Prev in Thread] Current Thread [Next in Thread]