Re: 'test' builtin of bash returns wrong value for '! -a FILE' operation
On Fri, Nov 05, 2010 at 04:24:23PM -0500, Jonathan Nieder wrote: > >>> Please try > >>> % bash -c 'test ! -a . && echo true' > >>> and compare with the result of > >>> % bash -c '/usr/bin/test ! -a . && echo true' imadev:~$ bash -c 'test ! -a . && echo true' true imadev:~$ bash -c '/usr/bin/test ! -a . && echo true' imadev:~$ This is an extremely convoluted example. You're echoing true if the object does NOT exist...? Actually, you're echoing true if the command fails to fail. In the /usr/bin/test -a case, the command has the right to fail because there's no such unary operator (see below), regardless of whether . exists in the file system. (On my system, there is no -a unary operator in the test(1) man page, but the command apparently supports one, undocumented. Isn't this fun?) > >> So which one is right? > > > > Both should echo "true", but the former did not: I found that the former > > sometimes returns the correct result, but have not found what makes the > > difference. POSIX does not specify -a as a unary operator. See http://www.opengroup.org/onlinepubs/9699919799/utilities/test.html for details. It specifies -a as a binary operator, but marks it as obsolescent and suggests using two test commands instead. This is the same advice I give whenever the subject comes up on IRC, and also what I mention on my pitfalls page: http://mywiki.wooledge.org/BashPitfalls#pf6 > Suggested changes: [...] I'll let Chet address those. Speaking strictly as someone who supports script writers (not shell maintainers), I'd suggest either using bash's [[ command instead of test, or avoiding the use of -a and -o in the test command. (Note that [[ uses && rather than -a, and || rather than -o. So whichever advice path you choose, -a and -o as binary operators are just plain bad.) If you're trying to determine whether some file-object exists, use -e. imadev:~$ bash -c 'test ! -e . && echo true' imadev:~$ bash -c '/usr/bin/test ! -e . && echo true' imadev:~$ If you're trying to run multiple tests, use multiple test commands, and string them together with && and/or || as required. imadev:~$ bash -c 'if test -e . && test -e ..; then echo true; fi' true imadev:~$ bash -c 'if /usr/bin/test -e . && /usr/bin/test -e ..; then echo true; fi' true Or use [[: imadev:~$ bash -c 'if [[ -e . && -e .. ]]; then echo true; fi' true
Re: Commands executed with $($prog) do not run properly
On Sat, Nov 06, 2010 at 03:09:08AM +0100, Hans-Georg Bork wrote: > $ prog='find /test -type d ! -wholename "/test"' > $ echo $prog > find /test -type d ! -wholename "/test" > $ echo "$($prog)" > /test > /test/c > /test/b > /test/d > /test/a > $ This is an error in your script, not in bash. You're passing literal double-quotes as part of an argument to find. find is therefore looking for files that have double-quotes in their name. If you wanted those double-quotes to be interpreted by bash, you would have to use eval. Of course, your double-quotes are not actually necessary in this example. Chances are you've obfuscated the original code What you're attempting *appears* to fall into this category: http://mywiki.wooledge.org/BashFAQ/050 -- I'm trying to put a command in a variable, but the complex cases always fail! I'd suggest reading that (and avoiding eval).
Re: crash when using associative array and integer variable
On 07/28/2010 08:46 AM, Roman Rakus wrote: Repeated in the bash-4.0.38 and bash-4.1.7 by the script; #!/bin/bash typeset -Ai s y='*' z='[' s[$y]=1 s[$z]=2 (( s[$z] = s[$z] + ${s[$y]} )) (( s[$y] = s[$y] + ${s[$z]} )) [[ ${s[$y]} = 4 ]] && echo "ok" FIX: added check; diff -up bash-4.1/variables.c.Ai bash-4.1/variables.c --- bash-4.1/variables.c.Ai 2010-07-28 08:42:54.0 +0200 +++ bash-4.1/variables.c2010-07-28 08:43:17.0 +0200 @@ -2371,7 +2371,7 @@ bind_int_variable (lhs, rhs) #endif v = bind_variable (lhs, rhs, 0); - if (isint) + if (isint && v) VSETATTR (v, att_integer); return (v); RR Any comments? RR
Re: Commands executed with $($prog) do not run properly
Hi, On Mon, 2010-11-08 at 08:51 -0500, Greg Wooledge wrote: > On Sat, Nov 06, 2010 at 03:09:08AM +0100, Hans-Georg Bork wrote: > > $ prog='find /test -type d ! -wholename "/test"' > > $ echo $prog > > find /test -type d ! -wholename "/test" > > $ echo "$($prog)" > > /test > > /test/c > > /test/b > > /test/d > > /test/a > > $ > > This is an error in your script, not in bash. You're passing literal > double-quotes as part of an argument to find. find is therefore looking > for files that have double-quotes in their name. if this is true, then please explain the differences between $ find /test -type d ! -wholename "/test" (/test not shown) and $ prog='find /test -type d ! -wholename "/test"' $ echo $prog find /test -type d ! -wholename "/test" $ echo "$($prog)" (/test shown) (more results in original mail) > If you wanted those double-quotes to be interpreted by bash, you would > have to use eval. Of course, your double-quotes are not actually > necessary in this example. Chances are you've obfuscated the original > code This were indeed just a simple example, the script where I use this set a complex find command with several -wholename options and there is also whitespace and wildcards in them. IMHO I'd need double-quotes with it; it is also explained that way in the man page of find. Thanks in advance. Regards --hgb
Re: crash when using associative array and integer variable
On 11/8/10 9:18 AM, Roman Rakus wrote: > On 07/28/2010 08:46 AM, Roman Rakus wrote: >> Repeated in the bash-4.0.38 and bash-4.1.7 by the script; >> #!/bin/bash >> >> typeset -Ai s >> y='*' >> z='[' >> s[$y]=1 >> s[$z]=2 >> (( s[$z] = s[$z] + ${s[$y]} )) >> (( s[$y] = s[$y] + ${s[$z]} )) >> [[ ${s[$y]} = 4 ]] && echo "ok" >> >> >> FIX: added check; >> diff -up bash-4.1/variables.c.Ai bash-4.1/variables.c >> --- bash-4.1/variables.c.Ai 2010-07-28 08:42:54.0 +0200 >> +++ bash-4.1/variables.c2010-07-28 08:43:17.0 +0200 >> @@ -2371,7 +2371,7 @@ bind_int_variable (lhs, rhs) >> #endif >> v = bind_variable (lhs, rhs, 0); >> >> - if (isint) >> + if (isint && v) >> VSETATTR (v, att_integer); >> >>return (v); >> >> RR >> > Any comments? It's a fair cop. The bug is real, and the patch is correct. The fix will be in bash-4.2. 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: Commands executed with $($prog) do not run properly
On Mon, Nov 08, 2010 at 03:26:10PM +0100, Hans-Georg Bork wrote: > if this is true, then please explain the differences between > $ find /test -type d ! -wholename "/test" > (/test not shown) > and > $ prog='find /test -type d ! -wholename "/test"' > $ echo $prog > find /test -type d ! -wholename "/test" > $ echo "$($prog)" > (/test shown) > (more results in original mail) imadev:~$ args find /test -type d ! -wholename "/test" 7 args: <-type> <-wholename> imadev:~$ prog='find /test -type d ! -wholename "/test"' imadev:~$ args $prog 7 args: <-type> <-wholename> <"/test"> "args" is a script that I have in ~/bin. Here is it: imadev:~$ cat bin/args #! /bin/sh printf "%d args:" $# printf " <%s>" "$@" echo I find it incredibly useful. So now, to answer your question, first I need to figure out what "-wholename" actually is. I suspect it's a GNU extension that aliases the -path extension...? Yeah. That's what the man page says. -wholename pattern See -path.This alternative is less portable than -path. OK, now let's see what you're doing: > $ find /test -type d ! -wholename "/test" So... you're trying to filter out the top-level directory itself from the set of results, right? imadev:~$ cd /tmp imadev:/tmp$ mkdir -p test/foo/bar; touch test/foo/bar/file imadev:/tmp$ find test -type d ! -path "test" test/foo test/foo/bar And then you're wondering why this "fails": imadev:/tmp$ find test -type d ! -path \"test\" test test/foo test/foo/bar You're asking it to filter out "test" but there is no "test". There is only test. Or in your original case, you were asking it to filter out "/test" but there was no "/test". There was only a /test directory. It didn't have literal double quotes in its name, but your argument to find DID have literal double quotes, so find was looking for them. > This were indeed just a simple example, the script where I use this set > a complex find command with several -wholename options and there is also > whitespace and wildcards in them. IMHO I'd need double-quotes with it; > it is also explained that way in the man page of find. GNU man page, I assume? The one in Debian 5.0 has this example: -path pattern File name matches shell pattern pattern. The metacharacters do not treat `/' or `.' specially; so, for example, find . -path "./sr*sc" This example is fine, and it demonstrates the use of quotes to protect a glob from exapansion BY A SHELL. But then the shell removes the quotes before passing the glob on to find. find should never see the actual quotes. If it does, it will treat them as literal. That is not what you want. In your code, you were passing literal quotes to find along with the directory name. This is why it failed. The workarounds if you absolutely positively MUST put the argument vector into a variable are (1) eval, or (2) an array. And I'd avoid eval if I were writing the script. It's extremely dangerous, especially if your arguments are as complex as you say. Since you appear not to have read http://mywiki.wooledge.org/BashFAQ/050 yet, let me do all the hard reading for you. This is what you SHOULD have used: prog=(find /test -type d ! -wholename "/test") echo "$( "${pr...@]}" )" And if I modify it slightly and use it, this is what it does: imadev:/tmp$ prog=(find test -type d ! -path "test") imadev:/tmp$ echo "$( "${pr...@]}" )" test/foo test/foo/bar You can put all the double triple quoted space glob metacharacter funny business you want inside array elements. Not inside scalar strings. http://mywiki.wooledge.org/BashFAQ/050
Re: Commands executed with $($prog) do not run properly
Hans-Georg Bork writes: > if this is true, then please explain the differences between > $ find /test -type d ! -wholename "/test" > (/test not shown) > and > $ prog='find /test -type d ! -wholename "/test"' > $ echo $prog > find /test -type d ! -wholename "/test" > $ echo "$($prog)" > (/test shown) > (more results in original mail) Do "set -x" and note the executed commands. 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: 'test' builtin of bash returns wrong value for '! -a FILE' operation
> "help test" says: > > See the bash manual page bash(1) for the handling of > parameters (i.e., missing parameters). > > which does not really tempt me to look at the manual. You should probably ask the person who added that to Debian's version of bash. > bash(1) says: > > Expressions may be combined using the following > operators, listed in decreasing order of precedence. The phrase you're quoting appears in both the description of the [[ conditional command and the test/[ builtin. If you're quoting the latter, why omit the next sentence, which reads: The evaluation depends on the number of arguments; see below. > 3 arguments > If the second argument is one of the > binary conditional operators listed above > under CONDITIONAL EXPRESSIONS, the result > of the expression is the result of the > binary test using the first and third > arguments as operands. The -a and -o > operators are considered binary operators > when there are three arguments. > > That answers the question. Unfortunately, the next sentence is > inconsistent with that answer: > >If the first > argument is !, the value is the negation of > the two-argument test using the second and > third arguments. > > Suggested changes: > > 1. Change the parenthesis in "help bash" to something like > "(e.g., operator precedence and missing parameters)". Again, talk to the Debian maintainer who added it. > 2. Change the second paragraph in the description in bash(1) of > the test builtin to something like > > Expressions may be combined using the following operators. > The evaluation depends on the number of arguments; see below. > When 5 or more arguments are present, this list is in > decreasing order of precedence. Something like that is reasonable. > 3. Add the word "Otherwise," before "If the first argument is !" in > the 3-argument case. The sentences are supposed to indicate precedence. It would actually be clearer if they were separated into bullet points, as they are in the Posix standard. I'll look at doing that. 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: Commands executed with $($prog) do not run properly
Hi, On Mon, 2010-11-08 at 09:49 -0500, Greg Wooledge wrote: > On Mon, Nov 08, 2010 at 03:26:10PM +0100, Hans-Georg Bork wrote: > > if this is true, then please explain the differences between > > $ find /test -type d ! -wholename "/test" > > (/test not shown) > > and > > $ prog='find /test -type d ! -wholename "/test"' > > $ echo $prog > > find /test -type d ! -wholename "/test" > > $ echo "$($prog)" > > (/test shown) > > (more results in original mail) > > imadev:~$ args find /test -type d ! -wholename "/test" > 7 args: <-type> <-wholename> > imadev:~$ prog='find /test -type d ! -wholename "/test"' > imadev:~$ args $prog > 7 args: <-type> <-wholename> <"/test"> this makes the whole thing now clear to me. I weren't aware that find doesn't strip the quotes on itself, but takes them as part of the pattern. > > "args" is a script that I have in ~/bin. Here is it: > > imadev:~$ cat bin/args > #! /bin/sh > printf "%d args:" $# > printf " <%s>" "$@" > echo > > I find it incredibly useful. I do as well now. I copied it. Thanks for that. > [...] > GNU man page, I assume? The one in Debian 5.0 has this example: > >-path pattern > File name matches shell pattern pattern. The metacharacters do > not treat `/' or `.' specially; so, for example, > find . -path "./sr*sc" > > This example is fine, and it demonstrates the use of quotes to protect > a glob from exapansion BY A SHELL. But then the shell removes the > quotes before passing the glob on to find. find should never see the > actual quotes. If it does, it will treat them as literal. That is not > what you want. There was my misunderstanding. Thanks again for pointing me to that. > > In your code, you were passing literal quotes to find along with the > directory name. This is why it failed. > > The workarounds if you absolutely positively MUST put the argument vector > into a variable are (1) eval, or (2) an array. And I'd avoid eval if I > were writing the script. It's extremely dangerous, especially if your > arguments are as complex as you say. > > Since you appear not to have read http://mywiki.wooledge.org/BashFAQ/050 > yet, let me do all the hard reading for you. I read it; it just has a lot about arguments. I didn't realize that I should translate it to commands as well. > This is what you SHOULD have used: > > prog=(find /test -type d ! -wholename "/test") > echo "$( "${pr...@]}" )" That example or a similar one would be nice in the FAQ. Thanks anyhow for the clarification and your patience with me. Regards -- hgb
Negative or zero arguments to yank-last-arg in bound keystrokes
Configuration Information [Automatically generated, do not change]: Machine: i686 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i686' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i686-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/local/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -g -O2 uname output: Linux hostname 2.6.31-21-generic #59-Ubuntu SMP Wed Mar 24 07:28:56 UTC 2010 i686 GNU/Linux Machine Type: i686-pc-linux-gnu Bash Version: 4.1 Patch Level: 9 Release Status: release Description: Negative or zero arguments to yank-last-arg in bound keystrokes do not perform as expected when the keystroke is pressed repeatedly. Comparing to yank-last-arg with no arguments or positive arguments which step backwards successively through history entries, when the argument is zero or negative, repeated keypresses only alternate between the two previous history entries. Also present in: GNU bash, version 4.1.0(1)-release (i686-pc-linux-gnu) GNU bash, version 4.0.33(1)-release (i486-pc-linux-gnu) GNU bash, version 3.2.51(24)-release (i686-pc-cygwin) Repeat-By: Create these keystroke bindings using whatever keystrokes you like. The demo below will use Alt-h, Alt-i, Alt-j, Alt-k and Alt-m: bind '"\eh": "\e1\e."' bind '"\ei": "\e0\e."' bind '"\ej": "\e-\e."' bind '"\ek": "\e-1\e."' bind '"\em": "\e-2\e."' Enter four example commands for testing. It doesn't matter what they are as long as they are different commands and have a few arguments that differ so it's easy to see the demonstration. printf '%s\n' foo bar echo aaa bbb ccc ls -ld . .. getent passwd root sys Press Alt-h four times, you should correctly get "passwd", "-ld", "aaa" and "'%s\n'" in succession. Clear the line (Ctrl-u). Alt-. also correctly gives "sys", "..", "ccc" and "bar". (Ctrl-u to clear) Now try the same thing with each of the other keystrokes, clearing the line between each test. Alt-i: Instead of "getent", "ls", "echo" and "printf" you will see "getent", "getent", "ls" and "getent". Subsequent repetitions will alternate between "ls" and "getent". Alt-j: Instead of "root", ".", "bbb" and "foo" you will see "root", "root", "." and "root". Subsequent repetitions will alternate between "." and "root". Alt-k: Same behavior as Alt-j. Alt-m: Instead of "passwd", "-ld", "aaa" and "'%s\n'" you will see "passwd", "passwd", "-ld" and "passwd". Subsequent repetitions will alternate between "-ld" and "passwd". Other negative arguments behave similarly.
Re: Ctrl- does nothing
Hello, `clear' command works. $TERM is linux, and xterm: I've tested in both TTYs, and X11 $ bind -p | grep clear "\C-l": clear-screen I've tried to un-bind (bind -r ^L), at this moment TTY beeps on Ctrl-L and re-bind (bind ^L:clear-screen): no beep, just new line the terminal can C-l, I use it with Debian's default /bin/bash (3.2.39(1)-release) but as soon as I go to /usr/local/bin/bash (where bash4 is), it doesn't work any more. Thank you for your interest.
Bash History Files
Hi, I use bash via Xterm. As a result I open multiple Xterm windows. When I type commands on the shell, they get saved only for that particular shell's history. I want to be able to collate that history, so that if I type commands on shell 1, I can search the same in the history of shell 2 in real time. I also want that this history be saved in a collated manner when I exit the shells. For example, the shell I and shell 2 should show the following: Shell1: bash> ls Shell2: bash> history ... ls (from Shell 1) history (from Shell 2) After Relogin, Shell1: bash> history ls (from Shell 1) history (from Shell 2) history (from Shell 1) Is there anything I could do? Regards, Ajay.