zsh-users
 help / color / mirror / code / Atom feed
* a 'require' function for zsh scripts and interactive functions
@ 2012-05-03 13:56 TJ Luoma
  2012-05-03 15:23 ` Bart Schaefer
  0 siblings, 1 reply; 3+ messages in thread
From: TJ Luoma @ 2012-05-03 13:56 UTC (permalink / raw)
  To: zsh-users

[-- Attachment #1: Type: text/plain, Size: 1117 bytes --]


I'm trying to come up with a function which will allow me to 'require' that a given command is found in $PATH, so I can put a line at the top of a script like this:

#!/bin/zsh

require gmv lynx wget

...

or in another function

foo () {

require bar

bar  
}

and know that the script will check to see if those are there before executing.

I have defined 'require' like this

require () {

for UTIL in $@
do

if (( $+commands[$UTIL] ))
then
:
else
msg "No $UTIL found"

if [[ "$SHLVL" == "1" ]]
then
return 1
else
exit 1
fi
fi

done
}



The SHLVL is intended to keep my login shell from exiting if a function doesn't find a required command.

The : in the if/else/fi is because I wasn't sure how else to do a "not" for (( $+commands[$UTIL] ))

(`msg` is just a fancy way of doing `echo` which uses `growlnotify` on Mac. http://luo.ma/msg)

When I finished creating `require`, I found myself wondering if I had just reinvented a wheel that zsh already implemented some other way, so I thought I'd ask. I also thought there might be other ways to improve this if zsh didn't already have something built-in.

TjL



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: a 'require' function for zsh scripts and interactive functions
  2012-05-03 13:56 a 'require' function for zsh scripts and interactive functions TJ Luoma
@ 2012-05-03 15:23 ` Bart Schaefer
  2012-05-03 20:37   ` Peter Stephenson
  0 siblings, 1 reply; 3+ messages in thread
From: Bart Schaefer @ 2012-05-03 15:23 UTC (permalink / raw)
  To: zsh-users

Att'n zsh-workers:  Possible bug noted at the very end of this reply.

On May 3,  9:56am, TJ Luoma wrote:
>
> I'm trying to come up with a function which will allow me to 'require'
> that a given command is found in $PATH, so I can put a line at the top
> of a script like this:

Wow, something did horrible things to your cut-and-paste.  I won't try
to excerpt your function here, but all leading whitespace is gone, and
no line wrapping in your paragraphs (I've reformatted the excerpts).
It looks like a bad html-to-text conversion.

> The SHLVL is intended to keep my login shell from exiting if a
> function doesn't find a required command.

More on this in a moment ...

> The : in the if/else/fi is because I wasn't sure how else to do a
> "not" for (( $+commands[$UTIL] ))

That one is simple:

      if ! (( $+commands[$UTIL] ))
or
      if (( $+commands[$UTIL] == 0 ))

> When I finished creating `require`, I found myself wondering if I had
> just reinvented a wheel that zsh already implemented some other way,

Look at the ${param:?message} expansion.

${NAME?WORD}
${NAME:?WORD}
     In the first form, if NAME is set, or in the second form if NAME
     is both set and non-null, then substitute its value; otherwise,
     print WORD and exit from the shell.  Interactive shells instead
     return to the prompt.  If WORD is omitted, then a standard message
     is printed.

The only tickler is that NAME and WORD aren't expanded in the output:

% print ${commands[$UTIL]?:No $UTIL found}
zsh: commands[$UTIL]: No $UTIL found

So your function is probably as good as anything, but if you want to
take advantage of the special behavior of :? for interactive shells you
can start with something like this:

  require () {
    setopt localtraps
    for UTIL
    do
      trap "msg 'No $UTIL found'" EXIT
      : ${commands[$UTIL]:?require failed}
    done
    trap - EXIT
  }

There's one more gotcha with that which may be a bug:  The EXIT trap is
skipped when the function returns with 'require failed' (but still run
by non-interactive shells when an actual exit occurs).  So you may have
to play around with "eval" and quoting to get decent output in your
terminal, but for non-interactive shells growl will pop up.

-- 
Barton E. Schaefer


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: a 'require' function for zsh scripts and interactive functions
  2012-05-03 15:23 ` Bart Schaefer
@ 2012-05-03 20:37   ` Peter Stephenson
  0 siblings, 0 replies; 3+ messages in thread
From: Peter Stephenson @ 2012-05-03 20:37 UTC (permalink / raw)
  To: zsh-users

On Thu, 03 May 2012 08:23:29 -0700
Bart Schaefer <schaefer@brasslantern.com> wrote:
>   require () {
>     setopt localtraps
>     for UTIL
>     do
>       trap "msg 'No $UTIL found'" EXIT
>       : ${commands[$UTIL]:?require failed}
>     done
>     trap - EXIT
>   }
> 
> There's one more gotcha with that which may be a bug:  The EXIT trap is
> skipped when the function returns with 'require failed' (but still run
> by non-interactive shells when an actual exit occurs).

It's not entirely clear whether it's correct, since we don't explicitly
define what it should do and EXIT traps in functions are specific to
zsh, but it's plausible.  The ":?"  syntax causes immediate exit from
the shell, or back to the prompt: in other words, it's treated as an
immediate error, i.e. the same as e.g.:

% fn() { trap 'echo EXITING' EXIT; echo ${**}; }
% fn
fn: bad substitution
% fn() { trap 'echo EXITING' EXIT; echo ${foo:?nope, sorry}; }
% fn
fn: foo: nope, sorry

The cases are, however, different when you're exiting the shell:

% zsh -fc 'trap "echo EXITING" EXIT; echo ${foo:?nope, sorry}' 
zsh:1: foo: nope, sorry
EXITING
% zsh -fc 'trap "echo EXITING" EXIT; echo ${**}'              
zsh:1: bad substitution

Bash calls the trap in both cases.

You can argue the function and shell cases are different since the ":?"
might be considered to cause the function to abort, with nothing more in
the main body of the script executing, but then the shell to exit
normally (apart from the status), so the EXIT trap would be run.

So there are actually 16 possibilities, though the realistic ones are
where the trap occurs additionally in one or more of the three remaining
cases.

You might well consider the most useful behaviour is for the trap
to happen in all cases, since it's there to clear up.

-- 
Peter Stephenson <p.w.stephenson@ntlworld.com>
Web page now at http://homepage.ntlworld.com/p.w.stephenson/


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2012-05-03 20:37 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-05-03 13:56 a 'require' function for zsh scripts and interactive functions TJ Luoma
2012-05-03 15:23 ` Bart Schaefer
2012-05-03 20:37   ` Peter Stephenson

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).