Re: 'test' builtin of bash returns wrong value for '! -a FILE' operation

2010-11-08 Thread Greg Wooledge
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

2010-11-08 Thread Greg Wooledge
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

2010-11-08 Thread Roman Rakus

 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

2010-11-08 Thread Hans-Georg Bork
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

2010-11-08 Thread Chet Ramey
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

2010-11-08 Thread Greg Wooledge
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

2010-11-08 Thread Andreas Schwab
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

2010-11-08 Thread Chet Ramey
> "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

2010-11-08 Thread Hans-Georg Bork
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

2010-11-08 Thread Dennis Williamson
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

2010-11-08 Thread humpty
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

2010-11-08 Thread Ajay Jain
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.