* Honoring a command @ 2004-04-01 17:03 DervishD 2004-04-03 21:43 ` Bart Schaefer 0 siblings, 1 reply; 5+ messages in thread From: DervishD @ 2004-04-01 17:03 UTC (permalink / raw) To: Zsh Users Hi all :) A couple of weeks ago one of the list members asked about justifying some script output, and I decided to er.. inspire from (that is, steal) that idea and I want to modify some scripts I have from something like: Printing file whatever.ps... done. to something like: Printing file whatever.ps [ok] justified to the screen width. This is not a problem since thanks to this list I know how to do the justification, but the question is that I want to modify code like this: print -n "Doing whatever command..." >&2 whatever.command 2> /dev/null || { print " error! Message" >&2; return 1; } print " done." >&2 to this: verbosely_do "Doing whatever command" whatever.command \ || { print "Message" >&2; return 1;} The function 'verbosely_do' is pretty easy: function verbosely_do() { emulate -L zsh print -n ${(r:(($WIDTH)):)1} >&2 $* || { print "[!]" >&2 return 1 } print "[*]" >&2 return 0 } $WIDTH is defined elsewhere or can be even a fixed number, and the symbols may have colors, etc... The important point is that the function prettyprints some messages and run the commands. Please, pretend that you don't notice that bare '$*' that may expand to an empty string ;)) That will corrected later. The problem I see is: what will happen if the command has redirections, metacharacters, quotes, variable references, etc.? Will it be run by 'verbosely_do' correctly, that is, exactly in the same way as it was run in the code without 'verbosely_do', or should I preprocess it in some way? As an example: verbosely_do "Command" chown -R `id -un`:`id -gn` "$SOURCES" Although it may be any command that will run correctly given itself alone in any script. Thanks a lot and please excuse me for such weird question O:) Raúl Núñez de Arenas Coronado -- Linux Registered User 88736 http://www.pleyades.net & http://raul.pleyades.net/ ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Honoring a command 2004-04-01 17:03 Honoring a command DervishD @ 2004-04-03 21:43 ` Bart Schaefer 2004-04-04 11:16 ` DervishD 0 siblings, 1 reply; 5+ messages in thread From: Bart Schaefer @ 2004-04-03 21:43 UTC (permalink / raw) To: Zsh Users On Apr 1, 7:03pm, DervishD wrote: } } [...] the question is that I want to modify code like this: } } print -n "Doing whatever command..." >&2 } whatever.command 2> /dev/null || { print " error! Message" >&2; return 1; } } print " done." >&2 } } } to this: } } verbosely_do "Doing whatever command" whatever.command \ } || { print "Message" >&2; return 1;} If you have access to the "initscripts" package, you might take a look at /etc/rc.d/init.d/functions -- particularly the "action" function that is defined in that file. It does pretty much exactly what your "verbosely_do" is meant to do (with the addition of wrapping the call in something called "initlog" which makes syslog entries for the command, but you can take that out). Something to note about that "action" function is that it folds the failure message into the wrapper function rather than following the wrapper call with an or-command. } The problem I see is: what will happen if the command has } redirections, metacharacters, quotes, variable references, etc.? Unless you quote them, they'll all be processed BEFORE verbosely_do is called, which may or may not do what you want. If you do quote them, then you'll probably need to use eval "$*" inside the verbosely_do function, which of course has it's own set of problems. As far as I can tell, the "action" function I mentioned assumes that there are no redirections and that it's OK for metachars and so on to have been expanded before the call. I'd also note that both "action" and "verbosely_do" are assuming that whatever.command does not produce any standard output of its own, or else that it's been redirected away somewhere (which is part of what "initlog" does, I think). Given that the command itself produces no output, you might consider something like this: verbosely_watch() { emulate -L zsh local output print -u2 -n ${(r:WIDTH:)1} if read output then print -u2 $output else print -u2 '[ok]' fi } TRAPZERR() { print '[fail]' } { whatever.command } 2>/dev/null | verbosely_watch "Doing whatever" That allows any syntax you like within the { }. ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Honoring a command 2004-04-03 21:43 ` Bart Schaefer @ 2004-04-04 11:16 ` DervishD 2004-04-05 1:09 ` Bart Schaefer 0 siblings, 1 reply; 5+ messages in thread From: DervishD @ 2004-04-04 11:16 UTC (permalink / raw) To: Bart Schaefer; +Cc: Zsh Users Hi Bart :) * Bart Schaefer <schaefer@brasslantern.com> dixit: > } verbosely_do "Doing whatever command" whatever.command \ > } || { print "Message" >&2; return 1;} > If you have access to the "initscripts" package, you might take a look > at /etc/rc.d/init.d/functions -- particularly the "action" function > that is defined in that file. It does pretty much exactly what your > "verbosely_do" is meant to do (with the addition of wrapping the call > in something called "initlog" which makes syslog entries for the > command, but you can take that out). I don't have that package (well, I've took a look at the initscripts package for Debian, but I think you were talking about the RPM one) > I'd also note that both "action" and "verbosely_do" are assuming that > whatever.command does not produce any standard output of its own, or > else that it's been redirected away somewhere (which is part of what > "initlog" does, I think). Yes, in all my shell functions the command does not spit anything through stdout (or has it redirected as well). That's the reason of the '2>' in my examples: I really don't care about stdout because it is handled, but stderr is not. > Given that the command itself produces no output, you might consider > something like this: Bart, you're a genius :)) This solution is simpler, more powerful and flexible since it doesn't pass the command as a parameter, shorter, easier to understand, does not mess a lot with AND lists or OR lists, etc... The number of beers I owe you is growing dangerously ;) > verbosely_watch() { > emulate -L zsh > local output > print -u2 -n ${(r:WIDTH:)1} > if read output > then > print -u2 $output > else > print -u2 '[ok]' > fi > } > > TRAPZERR() { print '[fail]' } > { whatever.command } 2>/dev/null | verbosely_watch "Doing whatever" I'm going to change it a bit, for not using TRAPZERR: I use it for other purpose in my scripts, although that doesn't seem to work :( (see below) verbosely_watch() { emulate -L zsh local output print -u2 -n ${(r:WIDTH:)1} if read output then print -u2 '[fail]' print $output else print -u2 '[ok]' fi } And after that, I'm going to use it as: { whatever.command 2> /dev/null || print "Error message"} \ | verbosely_watch "Doing whatever" I have the following alias, called 'scriptinit', which is called in all my scripts: alias scriptinit=$'emulate -L zsh ; trap \'return $LINENO\' ZERR' That way, anytime a script fails, its return code tells me the line the failure took place, and I can have silent scripts for some tasks, which still give information about what caused the error (if any). The problem is that it doesn't work with the above usage of verbosely_watch, because the trap is never run due to the OR list. I must replace: { whatever.command 2> /dev/null || print "Error message"} by: { whatever.command 2> /dev/null || print "Error message";false} for my generic trap to work :(, but then 'verbosely_watch' has no purpose at all! I think I'd better use 'scriptinit' only for muted scripts and verbosely_watch for the rest, using TRAPZERR for the error message. Is that a good idea? Thanks a lot Bart, as always. Raúl Núñez de Arenas Coronado -- Linux Registered User 88736 http://www.pleyades.net & http://raul.pleyades.net/ ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Honoring a command 2004-04-04 11:16 ` DervishD @ 2004-04-05 1:09 ` Bart Schaefer 2004-04-05 9:59 ` DervishD 0 siblings, 1 reply; 5+ messages in thread From: Bart Schaefer @ 2004-04-05 1:09 UTC (permalink / raw) To: Zsh Users On Apr 4, 1:16pm, DervishD wrote: } } The number of beers I owe you is growing dangerously ;) Especially considering that I rarely drink beer. Send me a six-pack of some unusual Spanish soft drink, or something. ;-} } alias scriptinit=$'emulate -L zsh ; trap \'return $LINENO\' ZERR' An interesting tidbit I just noticed -- if you read the script with the "source" or "." commands, $LINENO is reset to 1 when the trap runs, so you don't get as useful a return value. } The problem is that it doesn't work with the above usage of } verbosely_watch, because the trap is never run due to the OR list. I } must replace: } } { whatever.command 2> /dev/null || print "Error message"} } } by: } } { whatever.command 2> /dev/null || print "Error message";false} Actually that won't work either, because that _always_ executes "false". I think you meant { whatever.command 2> /dev/null || { print "Error message";false } } } but then 'verbosely_watch' has no purpose at all! You could write another little function: verbosely_fail() { local ret=$? [[ -p /dev/fd/1 ]] && print "$*" return ret } Now this works: { whatever.command || verbosely_fail "Error message" } 2>/dev/null | verbosely_watch "Doing whatever" If you DON'T pipe to verbosely_watch, then verbosely_fail is silent and the ZERR trap returns the line number as $?. (Even if you do pipe it, the line number is stored in $pipestatus[1], which may be useful for other tricks.) } I think I'd better use 'scriptinit' only for muted } scripts and verbosely_watch for the rest, using TRAPZERR for the } error message. Is that a good idea? That would work as well, but it means the error message is the same for every command (unless you re-assign it somehow each time). ^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Honoring a command 2004-04-05 1:09 ` Bart Schaefer @ 2004-04-05 9:59 ` DervishD 0 siblings, 0 replies; 5+ messages in thread From: DervishD @ 2004-04-05 9:59 UTC (permalink / raw) To: Bart Schaefer; +Cc: Zsh Users Hi Bart :) * Bart Schaefer <schaefer@brasslantern.com> dixit: > } The number of beers I owe you is growing dangerously ;) > Especially considering that I rarely drink beer. Send me a six-pack of > some unusual Spanish soft drink, or something. ;-} I think the only soft drinks we have in Spain are from abroad, but I'll take a look ;)) > } alias scriptinit=$'emulate -L zsh ; trap \'return $LINENO\' ZERR' > An interesting tidbit I just noticed -- if you read the script with the > "source" or "." commands, $LINENO is reset to 1 when the trap runs, so > you don't get as useful a return value. I know, but I never source that scrips (is there any way to make a script as 'unsourceable' :?). This ZERR thing for returning an error code is not very solid :( I should work in a better one, but I had never the need O:) > } { whatever.command 2> /dev/null || print "Error message";false} > Actually that won't work either, because that _always_ executes "false". > I think you meant > { whatever.command 2> /dev/null || { print "Error message";false } } Yes, I forgot the braces, sorry O:) > } but then 'verbosely_watch' has no purpose at all! > You could write another little function: > verbosely_fail() { > local ret=$? > [[ -p /dev/fd/1 ]] && print "$*" > return ret > } That's nice :) > > Now this works: > > { whatever.command || verbosely_fail "Error message" } 2>/dev/null | > verbosely_watch "Doing whatever" > > If you DON'T pipe to verbosely_watch, then verbosely_fail is silent and the > ZERR trap returns the line number as $?. (Even if you do pipe it, the line > number is stored in $pipestatus[1], which may be useful for other tricks.) > > } I think I'd better use 'scriptinit' only for muted > } scripts and verbosely_watch for the rest, using TRAPZERR for the > } error message. Is that a good idea? > That would work as well, but it means the error message is the same for > every command (unless you re-assign it somehow each time). That's not a problem, I can use a global variable for the message and reassign it before each command is run, instead of redefining TRAPZERR (and obviously I must make TRAPZERR output that variable). Finally I think that the solution I'm going to adopt is the function 'verbosely_watch', TRAPZERR for the error message instead the OR list. I'm afraid that using ZERR to return the line number of the error is only useful for debugging, to know where a bug happened, but for production scripts I think is better to have a reduced and well defined set of error return codes. Thanks a lot for your, as always, invaluable help. Raúl Núñez de Arenas Coronado -- Linux Registered User 88736 http://www.pleyades.net & http://raul.pleyades.net/ ^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2004-04-05 10:18 UTC | newest] Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2004-04-01 17:03 Honoring a command DervishD 2004-04-03 21:43 ` Bart Schaefer 2004-04-04 11:16 ` DervishD 2004-04-05 1:09 ` Bart Schaefer 2004-04-05 9:59 ` DervishD
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).