Re: conditional aliases are broken
On 8/19/11 6:38 AM, Roman Rakus wrote: > On 08/18/2011 07:57 PM, Eric Blake wrote: >> On 08/18/2011 08:53 AM, Roman Rakus wrote: >>> On 08/18/2011 04:38 PM, Sam Steingold wrote: how do I write a function that would print the same as $ \ls | cat >>> f3(){ printf "%s\n" "$@"; } >> >> "\n" looks funny in shell; even though POSIX requires that "\n" does not >> treat the \ as an escape but as a literal character, stylistically, I >> prefer writing "\\n" or '\n' to make it clear that I intended a literal >> backslash. >> > Interesting. I would expect that "\\n" in printf will print out `\n'. Good > to know. printf performs its own backslash interpretation of the format string, so Eric's point is that any word expansions may reduce the number of backslashes printf sees. This depends on the character following the backslash, since double quotes enable backslash interpretation for only a few specific characters. "\n" will remain unchanged, since the `n' is not one of the characters for which backslash is special, but "\\n" will be expanded to "\n". "\\n" will be transformed to "\n" by the time printf sees it, and printf will translate that to newline. '\\n' will be displayed as you expect. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: conditional aliases are broken
On 08/18/2011 07:57 PM, Eric Blake wrote: On 08/18/2011 08:53 AM, Roman Rakus wrote: On 08/18/2011 04:38 PM, Sam Steingold wrote: how do I write a function that would print the same as $ \ls | cat f3(){ printf "%s\n" "$@"; } "\n" looks funny in shell; even though POSIX requires that "\n" does not treat the \ as an escape but as a literal character, stylistically, I prefer writing "\\n" or '\n' to make it clear that I intended a literal backslash. Interesting. I would expect that "\\n" in printf will print out `\n'. Good to know. RR
Re: conditional aliases are broken
On 8/18/11 11:58 AM, Greg Wooledge wrote: > It would appear "declare -g" does NOT allow you to "jump over" a local > variable that is shadowing a global. That's disappointing. That is not its intent. The very narrow purpose of declare -g is to allow you to declare a variable with attributes in a function without the variable becoming local. It doesn't change variable scoping rules or variable name resolution behavior. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: conditional aliases are broken
On 08/18/2011 08:53 AM, Roman Rakus wrote: On 08/18/2011 04:38 PM, Sam Steingold wrote: how do I write a function that would print the same as $ \ls | cat f3(){ printf "%s\n" "$@"; } "\n" looks funny in shell; even though POSIX requires that "\n" does not treat the \ as an escape but as a literal character, stylistically, I prefer writing "\\n" or '\n' to make it clear that I intended a literal backslash. -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org
Re: conditional aliases are broken
On 08/18/2011 11:38 AM, Stefano Lattarini wrote: Hi Eric. On Thursday 18 August 2011, Eric Blake wrote: On 08/18/2011 08:44 AM, Eric Blake wrote: how do I write a function that would print the same as $ \ls | cat Useless use of cat. This can be done with \ls -1. f(){ for a in "$@"; do echo "$a"; done; } Actually, echo "$a" is not portable - if you have any file names beginning with - or containing \, then the results can be corrupted. Or skip the loop altogether: f(){ printf %s\\n "%@"; } I think you've made a typo here; it should have been: f () { printf %s\\n "$@"; } Yep, slip of one key when I typed (at least on my keyboard, % and $ are neighbors). I guess that's what you meant, right? BTW, is this behaviour truly portable to other shells and/or printf utilities? POSIX seems to require it to portable, but you never know ... It's portable, but not always fast (some shells lack printf(1) as a builtin, and end up spawning a process). And in the case of arbitrary file names, printf is always better than echo, since it handles \ and leading - correctly. -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org
Re: conditional aliases are broken
On Thursday 18 August 2011, Stefano Lattarini wrote: > Hi Eric. > > On Thursday 18 August 2011, Eric Blake wrote: > > On 08/18/2011 08:44 AM, Eric Blake wrote: > > >> how do I write a function that would print the same as > > >> $ \ls | cat > > > > Useless use of cat. This can be done with \ls -1. > > > > > f(){ for a in "$@"; do echo "$a"; done; } > > > > Or skip the loop altogether: > > > > f(){ printf %s\\n "%@"; } > > > I think you've made a typo here; it should have been: > > f () { printf %s\\n "$@"; } > > I guess that's what you meant, right? > > BTW, is this behaviour truly portable to other shells and/or printf > utilities? POSIX seems to require it to portable, but you never > know ... > Sorry, I've seen Roman's answer just now; feel free to ignore my mail. Sorry for the noise, Stefano
Re: conditional aliases are broken
Hi Eric. On Thursday 18 August 2011, Eric Blake wrote: > On 08/18/2011 08:44 AM, Eric Blake wrote: > >> how do I write a function that would print the same as > >> $ \ls | cat > > Useless use of cat. This can be done with \ls -1. > > > f(){ for a in "$@"; do echo "$a"; done; } > > Or skip the loop altogether: > > f(){ printf %s\\n "%@"; } > I think you've made a typo here; it should have been: f () { printf %s\\n "$@"; } I guess that's what you meant, right? BTW, is this behaviour truly portable to other shells and/or printf utilities? POSIX seems to require it to portable, but you never know ... Regards, Stefano
Re: conditional aliases are broken
` Greg Wooledge wrote: On Thu, Aug 18, 2011 at 08:03:41AM -0700, Linda Walsh wrote: 4.2 introduce a new -g to declare a global variable inside a function. Which doesn't say what it would do in situations like the above. Then let's test: imadev:~$ echo $BASH_VERSION 4.2.10(7)-release imadev:~$ unset a b; unset -f f1 f2 imadev:~$ f1() { local a='tmp'; f2; } imadev:~$ f2() { declare -g a b; a=3 b=5; } imadev:~$ a=a b=b; f1; echo "a=<$a> b=<$b>" a= b=<5> It would appear "declare -g" does NOT allow you to "jump over" a local variable that is shadowing a global. That's disappointing. When I asked about defining a local var in a command in the context of the caller, -- greg didn't even think of aliases, just inferred it couldn't be done except by doing it in the caller -- i.e. manually typing it in each time.. Not good! If you're going to use the "magic aliases" or "upvar" hacks in your scripts, please don't ever ask me to debug them. --- Not using any "magic aliases -- just aliases -- but since you didn't know about aliases, then by definition ALL aliases are magic, so you got me there!...Aliases are like "macros" (but w/o param substitution). They are used in all sorts of languages usefully and aren't considered an impediment to programing or understand -- when used rationally and in defined ways! Sure, you can write garbage, but the point here is whether or not I an increase readability and understanding by using an alias vs. not. Be fair -- your question did not ask how to do "call by reference" in bash. --- EXACTLY...I didn't bring up 4.2... You asked a very specific thing, and I gave a very specific answer and example. If you had wanted arbitrary call-by-reference then I would have pointed you back to FAQ 6. --- Not knowing it by heart, I'll just say -- I wasn't asking for a general C-B-R, I just wanted bash to handle ${#[@]}, where word can now only be a simple name of an array, but ''COULD" be a subexpression that returns the name of an array...just that the parser isn't that bright. Please don't ask me to defend a position that I didn't take! I'd have to do preparation first, and I'm not sure I'd want to argue that position! ;-) It's not that I "didn't think of" things. It's that I *have* thought about them in the past several years, and I know what is reasonable and what is not. Certain things cannot be achieved reasonably in bash, and so we *don't do them* in bash, and we advise other people not to do them either. I didn't ask for anything unreasonable. But you didn't know about bash's builtin macro ability being an ajunct to it's functions, so you would rule out using many useful paradigms in bash that bash would support just fine. If you had known the usefulness of "-e", in 3.0-4.0, you might have made use of it. now its broken garbage -- have to follow every expression with ||: that's so attractive! not to mention the ~5% performance it for taking the or on the : expression (from primitive timings)... Well, if you remember, this was a 4-bullet list of things to do, -- it's been adding all the error checking and interlocks (as well as LOTS of debug code) that have made it as complex as it is As for the case of needs to use macros(aliases)-- besides setting var s in the right context, there's also setting *flags* (to set) in the correct context. Here was my usage: (in the lib file)... alias DebugPop='test -n "$save_ops" && set -$save_ops' alias DebugPop_preserve_status='local stat=$?;test -n "$save_ops" && { set -$save_ops; }; return $stat;' function DebugPush_helper { local dbgflgs="${-:-}";set +x; local flag="${1:?}" if chkflg Trace_off "$flag";then dbgflgs="${dbgflgs//x/}" ;fi if chkflg Trace_on "$flag" ;then dbgflgs="${dbgflgs}x" ;fi if chkflg Local_Debug "$flag" ; then _Debug=1; else _Debug=0; fi test -n "$dbgflgs" && set -$dbgflgs return 0 } alias DebugPush='local save_ops="${-:-}" _Debug=; DebugPush_helper' I haven't used the preserve status one, as haven't needed it, but threw it in as I thought I might. But in both cases any debug ops altered for the routine this was called in, are 'reset' upon exit, so I can turn on/off tracing in a function (or set other flags "+/-eu"...etc..., as well as set a func-specific debug flag. The resulting code is much cleaner looking than any of the alternatives: function get_devname_of_mp { DebugPush MP_OPS if (($# < 1 )); then ; DebugPop; errx -9 "Internal error: ..."; fi local mp="${1:?}" local dev="$($_grep -P '\s'"$mp"'\s' /proc/mounts|$_cut -d\ -f1)" echo "$dev" DebugPop }
Re: conditional aliases are broken
On Thu, Aug 18, 2011 at 08:03:41AM -0700, Linda Walsh wrote: > >4.2 introduce a new -g to declare a global variable inside a function. > >Which doesn't say what it would do in situations like the above. Then let's test: imadev:~$ echo $BASH_VERSION 4.2.10(7)-release imadev:~$ unset a b; unset -f f1 f2 imadev:~$ f1() { local a='tmp'; f2; } imadev:~$ f2() { declare -g a b; a=3 b=5; } imadev:~$ a=a b=b; f1; echo "a=<$a> b=<$b>" a= b=<5> It would appear "declare -g" does NOT allow you to "jump over" a local variable that is shadowing a global. That's disappointing. > When I asked about defining a local var in a command in the context > of the caller, -- greg didn't even think of aliases, just inferred it > couldn't be done except by doing it in the caller -- i.e. manually > typing it in each time.. Not good! If you're going to use the "magic aliases" or "upvar" hacks in your scripts, please don't ever ask me to debug them. Be fair -- your question did not ask how to do "call by reference" in bash. You asked a very specific thing, and I gave a very specific answer and example. If you had wanted arbitrary call-by-reference then I would have pointed you back to FAQ 6. If you want call-by-ref for arrays, then I will repeat my recommendation that you use ksh93 which has an actual language feature for this, not bash, which doesn't. It's not that I "didn't think of" things. It's that I *have* thought about them in the past several years, and I know what is reasonable and what is not. Certain things cannot be achieved reasonably in bash, and so we *don't do them* in bash, and we advise other people not to do them either. Does this mean they're impossible? Maybe not. But it means they are not a good idea! We have all these other languages we could use instead, where these tasks *can* be achieved reasonably. When you run into such a task, it makes much more sense to switch to a language that's suited to it, rather than using arcane trickery.
Re: conditional aliases are broken
Pierre Gaston wrote: Is this a question? or are you trying to make a point? It is both -- a chance to find answer to a question, or make the point that aliases in scripts have a useful purposes that can't be replaced by function clls. For the question (If I understand correctly): 1) Most variables don't need to be declared in bash. But in doing so, you end up with non-deterministic behavior depending on who was in your call stack: Ex: a=1 b=2 function c { a=3 b=5; } c; echo $a, $b 3, 5 # perfectly reasonable Now supposed 'c' is called by another function 'a': function a { local a='tmp' ; c } a=1 b=2 a; echo $a $b 1,5 # IF the same person wrote both, then maybe they won't be surprised at the behavior, but it certainly would be regarded as unpredictable, depending on how intervening functions, -- hardly a great design point, thought it can allow for some inscrutably designed programs! The above situation can be worse: a=1 b=2 function c { ((a*=3))||: ; ((b*=5))||: ; } c; echo $a, $b 3, 10 # but insert 'a' into the stream function a { local a='tmp' ; c } a=1 b=2 # now instead of unexpected output we get: a -bash: ((: a: expression recursion level exceeded (error token is "a") Thus are some examples of dangers in NOT declaring vars in sub functions. .2 introduce a new -g to declare a global variable inside a function. Which doesn't say what it would do in situations like the above. Does it declare globals that will have an 'empty value' above the ones declared in the main prog? then trying to use them as in a*=3, b=*=5 would result in failure as the global vars would be uninitialized. Anyway, hopefully some problems will be fixed in by 4.2, especially things like pressing tab on blank lines inside a single quote expanding to all of your local filenames -- usually expansions are not performed inside a single quote == let alone having it desirable to try to expand null / empty strings when the option to do so is turned off. For the point: Yes the manual says "most" not "all", one interesting hack with aliases is: http://www.chiark.greenend.org.uk/~sgtatham/aliases.html Indeed. Some for get the "most" part... When I asked about defining a local var in a command in the context of the caller, -- greg didn't even think of aliases, just inferred it couldn't be done except by doing it in the caller -- i.e. manually typing it in each time.. Not good!
Re: conditional aliases are broken
On 08/18/2011 04:38 PM, Sam Steingold wrote: how do I write a function that would print the same as $ \ls | cat f3(){ printf "%s\n" "$@"; } But please move your question like "HOW TO..." somewhere else; comp.unix.shell usenet group or the #bash IRC channel on freenode or... This mailing list is about bugs in bash. RR
Re: conditional aliases are broken
On 08/18/2011 08:44 AM, Eric Blake wrote: how do I write a function that would print the same as $ \ls | cat Useless use of cat. This can be done with \ls -1. f(){ for a in "$@"; do echo "$a"; done; } Or skip the loop altogether: f(){ printf %s\\n "%@"; } -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org
Re: conditional aliases are broken
On 08/18/2011 08:38 AM, Sam Steingold wrote: mkdir z cd z touch a b 'c d' When doing exercises like this, I like to: touch a b 'c d' Notice the double spacing - it proves whether I used enough quoting throughout the exercise - if 'c d' with one space shows up anywhere, then I missed quoting, because word splitting followed by argument concatenation with only one space must have happened. how do I write a function that would print the same as $ \ls | cat a b c d $ f1(){ for a in "$*"; do echo $a; done; } Incorrect quoting on $a. Also, remember the difference between $* and $@ inside "" - the former creates only one word, and only the latter splits the result into the same number of words as were originally arguments to the function. You meant: f(){ for a; do echo "$a"; done; } or f(){ for a in "$@"; do echo "$a"; done; } (both are identical). -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org
Re: conditional aliases are broken
> * Eric Blake [2011-08-15 16:59:29 -0600]: > > On 08/15/2011 04:40 PM, Sam Steingold wrote: >>> * Andreas Schwab [2011-08-15 22:04:04 +0200]: >>> >>> Sam Steingold writes: >>> Cool. Now, what does this imply? >>> >>> "For almost every purpose, shell functions are preferred over aliases." >> >> so, how do I write >> >> alias a=b >> >> as a function? >> (remember that arguments may contain spaces&c) > > a() { b "$@"; } mkdir z cd z touch a b 'c d' how do I write a function that would print the same as $ \ls | cat a b c d $ $ f1(){ for a in "$*"; do echo $a; done; } $ f1 * a b c d $ $ f2(){ for a in $*; do echo $a; done; } $ f2 * a b c d $ -- Sam Steingold (http://sds.podval.org/) on CentOS release 5.6 (Final) X 11.0.60900031 http://ffii.org http://honestreporting.com http://www.memritv.org http://thereligionofpeace.com http://mideasttruth.com http://dhimmi.com UNIX is a way of thinking. Windows is a way of not thinking.
Re: conditional aliases are broken
On Wed, Aug 17, 2011 at 08:46:34PM -0700, Linda Walsh wrote: > how do you declare a variable for storage in the context of the caller? > (using a function)... > ??? The *caller* declares it. > I found it very troublesome > inside a function, to store a value into a local variable in the caller. caller() { local x=0 callee echo "x is <$x>" } callee() { x=42 } caller
Re: conditional aliases are broken
On Thu, Aug 18, 2011 at 6:46 AM, Linda Walsh wrote: > > > > ` Eric Blake wrote: >> >> On 08/15/2011 04:40 PM, Sam Steingold wrote: * Andreas Schwab [2011-08-15 22:04:04 +0200]: Sam Steingold writes: > > Cool. Now, what does this imply? "For almost every purpose, shell functions are preferred over aliases." >>> >>> so, how do I write >>> alias a=b >>> as a function? >>> (remember that arguments may contain spaces&c) >> >> a() { b "$@"; } > > --- > Way too easy. > how do you declare a variable for storage in the context of the caller? > (using a function)... > ??? > > The DebugPush & DebugPop routines I used needed to store > the current func's flags in it's context -- I found it very troublesome > inside a function, to store a value into a local variable in the caller. Is this a question? or are you trying to make a point? For the question (If I understand correctly): 1) Most variables don't need to be declared in bash. 2) bash4.2 introduce a new -g to declare a global variable inside a function. For the point: Yes the manual says "most" not "all", one interesting hack with aliases is: http://www.chiark.greenend.org.uk/~sgtatham/aliases.html
Re: conditional aliases are broken
` Eric Blake wrote: On 08/15/2011 04:40 PM, Sam Steingold wrote: * Andreas Schwab [2011-08-15 22:04:04 +0200]: Sam Steingold writes: Cool. Now, what does this imply? "For almost every purpose, shell functions are preferred over aliases." so, how do I write alias a=b as a function? (remember that arguments may contain spaces&c) a() { b "$@"; } --- Way too easy. how do you declare a variable for storage in the context of the caller? (using a function)... ??? The DebugPush & DebugPop routines I used needed to store the current func's flags in it's context -- I found it very troublesome inside a function, to store a value into a local variable in the caller.
Re: conditional aliases are broken
On 08/15/2011 04:40 PM, Sam Steingold wrote: * Andreas Schwab [2011-08-15 22:04:04 +0200]: Sam Steingold writes: Cool. Now, what does this imply? "For almost every purpose, shell functions are preferred over aliases." so, how do I write alias a=b as a function? (remember that arguments may contain spaces&c) a() { b "$@"; } -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org
Re: conditional aliases are broken
> * Andreas Schwab [2011-08-15 22:04:04 +0200]: > > Sam Steingold writes: > >> Cool. Now, what does this imply? > >"For almost every purpose, shell functions are preferred over aliases." so, how do I write alias a=b as a function? (remember that arguments may contain spaces &c) -- Sam Steingold (http://sds.podval.org/) on CentOS release 5.6 (Final) X 11.0.60900031 http://mideasttruth.com http://camera.org http://pmw.org.il http://iris.org.il http://ffii.org http://thereligionofpeace.com A poet who reads his verse in public may have other nasty habits.
Re: conditional aliases are broken
Sam Steingold writes: > Cool. Now, what does this imply? "For almost every purpose, shell functions are preferred over aliases." Andreas. -- Andreas Schwab, sch...@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different."
Re: conditional aliases are broken
On 08/15/2011 01:10 PM, Sam Steingold wrote: * Andreas Schwab [2011-08-15 18:42:30 +0200]: Sam Steingold writes: this works: $ alias z='echo a' $ zz(){ z b; } $ zz a b however, after sourcing this file: if true; then alias z='echo a' zz(){ z b; } fi Aliases are expanded during reading, but the alias command isn't executed until after the complete compound command was read. Cool. Now, what does this imply? Is this the expected behavior aka "feature"? Yep - feature. All shells behave that way. They parse to an end of a command (in your case, the end of the compound 'if-fi' command), then process statements within the command. Alias expansion affects parsing, so your alias cannot take effect until after the compound command has been parsed, and all attempts to use the alias from within the compound command were parsed with the pre-command expansion (ie. no alias). Yet another reasons why aliases are mostly replaced by functions. -- Eric Blake ebl...@redhat.com+1-801-349-2682 Libvirt virtualization library http://libvirt.org
Re: conditional aliases are broken
> * Andreas Schwab [2011-08-15 18:42:30 +0200]: > > Sam Steingold writes: > >> this works: >> >> $ alias z='echo a' >> $ zz(){ z b; } >> $ zz >> a b >> >> however, after sourcing this file: >> if true; then >> alias z='echo a' >> zz(){ z b; } >> fi > > Aliases are expanded during reading, but the alias command isn't > executed until after the complete compound command was read. Cool. Now, what does this imply? Is this the expected behavior aka "feature"? -- Sam Steingold (http://sds.podval.org/) on CentOS release 5.6 (Final) X 11.0.60900031 http://mideasttruth.com http://palestinefacts.org http://truepeace.org http://iris.org.il http://www.PetitionOnline.com/tap12009/ Apathy Club meeting this Friday. If you want to come, you're not invited.
Re: conditional aliases are broken
Sam Steingold writes: > this works: > > $ alias z='echo a' > $ zz(){ z b; } > $ zz > a b > > however, after sourcing this file: > if true; then > alias z='echo a' > zz(){ z b; } > fi Aliases are expanded during reading, but the alias command isn't executed until after the complete compound command was read. Andreas. -- Andreas Schwab, sch...@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different."