Re: change in behavior starting with bash-4.3_p14 and $@ in [[...]]

2014-08-13 Thread Chet Ramey
-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

On 8/12/14, 11:05 PM, Mike Frysinger wrote:
> simple enough code:
> foo=(0 0 0); [[ -z ${foo[@]#0} ]]; echo $?
> 
> with bash-4.3_p13 and older, this would show 0.  starting with bash-4.3_p14, 
> this now shows 1.

It's intentional, and part of the same bug fix.  Word splitting is
suppressed inside [[, so the array expands to a single word ("0 0 0"), the
0s are removed, leaving "  ", and that is the result the current version
uses.  The code before patch 14 ran the string through word splitting,
which removed the spaces.  FWIW, ksh93 returns the same result as the
patched bash, though I can't tell whether it's doing the exact same thing
internally.

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/
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.11 (Darwin)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iEYEARECAAYFAlPrbIcACgkQu1hp8GTqdKtKBwCeJrFBvXyzXEzL/HABKzS1ZS/x
32sAn3PEPcEPfUuTRXCHPT+KLWimMJsf
=T5NC
-END PGP SIGNATURE-



Re: change in behavior starting with bash-4.3_p14 and $@ in [[...]]

2014-08-13 Thread Greg Wooledge
On Wed, Aug 13, 2014 at 09:47:51AM -0400, Chet Ramey wrote:
> On 8/12/14, 11:05 PM, Mike Frysinger wrote:
> > foo=(0 0 0); [[ -z ${foo[@]#0} ]]; echo $?

> Word splitting is
> suppressed inside [[, so the array expands to a single word ("0 0 0"), the
> 0s are removed, leaving "  "

That doesn't sound right.  Either you get a single word and remove the
leading 0 only, or you remove the 0s from each array element first,
and then get a single word by concatenating what's left.

The code that Mike posted is pretty wonky in the first place.  I don't
understand what its intent is.  (It's expanding an array into a list of
words in a context where you can't have a list... and then checking the
string length of that list-not-list as if it were a string... what?)

The right-hand side of an assignment also suppresses word splitting, so
I tried this:

imadev:~$ foo=(0 0 0); x=${foo[@]#0}
imadev:~$ echo "<$x>"
<>
imadev:~$ foo=(0 0 0); x="${foo[@]#0}"
imadev:~$ echo "<$x>"
<  >
imadev:~$ echo $BASH_VERSION
4.3.22(5)-release

Looks like the second one expanded to a list of empty words and then
concatenated them together with spaces.  I have no idea what the first
one did, or why it's different.



Cannot trap INT in child of an interactive shell

2014-08-13 Thread Greg Wooledge
Bash 4.3.22, HP-UX.

imadev:~$ child() { trap - INT; trap 'echo I got an INT; trap - INT; kill -INT $
BASHPID' INT; while true; do sleep 1; done; }; child &
[1] 19116
imadev:~$ kill -INT 19116
imadev:~$ kill -INT 19116
imadev:~$ kill -TERM 19116
[1]+  Terminated  child

The manual says:

  Non-builtin commands run by bash have signal handlers set to the
  values inherited by the shell from its parent.  When job control is
  not in effect, asynchronous commands ignore SIGINT and SIGQUIT in
  addition to these inherited handlers.

And yes, turning on job control magically makes it work:

imadev:~$ child() { set -m; trap - INT; trap 'echo I got an INT; trap - INT; kil
l -INT $BASHPID' INT; while true; do sleep 1; done; }; child &
[1] 19127
imadev:~$ kill -INT 19127
imadev:~$ I got an INT

[1]+  Interrupt   child

But I don't understand why job control is needed to override an inherited
(or automatically created) trap.  Shouldn't an explicit trap always be
used?

Ksh (88) does not have this problem:

imadev:~$ ksh
$ child() { trap - INT; trap 'echo I got an INT; trap - INT; kill -INT 
$BASHPID' INT; while true; do sleep 1; done; }; child &
[1] 19133
$ kill -INT 19133
$ I got an INT
child: kill: bad argument count

(Of course, ksh also doesn't have BASHPID, so ignore that last bit.)



Re: Feature request - ganged file test switches

2014-08-13 Thread Steve Simmons

On Aug 12, 2014, at 4:36 PM, Chet Ramey  wrote:

> On 8/9/14, 7:07 AM, Steve Simmons wrote:
> 
>> It would be nice to have ganged file test switches. As an example, to test 
>> that a directory exists and is properly accessible one could do
>> 
>>  if [[ -d foo ]] && [[ -r foo ]] && [[ -x foo ]] ; then . . .
>> 
>> but
>> 
>>  if [[ -drx foo ]] ; then . . .
>> 
>> is a lot easier.
> 
> Sure, but it's only syntactic sugar.

Knew that going in :-). Other discussion points out how limited it is; I'm 
perfectly happy pulling back. My thoughts on how to do this more flexibly boil 
down to the capabilities gnu find has w/r/t file types and modes. Unfortunately 
we have a few systems which lack gnu find and are "vendor supported appliances" 
(eyeroll) and we're unable to add new software beyond simple scripts. Which 
also means that any new bash feature would probably be unavailable for years, 
so it's not like this is a big loss.

If others have no interest in this syntactic sugar I see little point to adding 
it; a broader and more flexible solution is just to use find as above.


Script with set -m launched from interactive shell makes all ancestor shells die

2014-08-13 Thread Greg Wooledge
This was tested on bash 4.3.22 (HP-UX) and bash 4.2.37 (Linux).

Create a script named foo with the following content:

#!/bin/bash
set -m
while sleep 1; do :; done

Make it executable, and type

./foo &

at an interactive shell.  You get your shell prompt back.  You can press
Enter as many times as you like.  But if you press any key other than
Enter, the entire terminal window goes away.

Wrapping a few shells around it only postpones the inevitable.  If you
run a few nested "bash" shells as padding, and then run ./foo & in the
innermost one, each non-Enter keystroke will kill one instance of bash,
printing the word "exit" on the terminal.  When all the shells die,
so does the terminal.

wooledg@wooledg:~$ bash
wooledg@wooledg:~$ bash
wooledg@wooledg:~$ bash
wooledg@wooledg:~$ bash
wooledg@wooledg:~$ ./foo &
[1] 11945
wooledg@wooledg:~$ aexit
wooledg@wooledg:~$ bexit
wooledg@wooledg:~$ cexit
wooledg@wooledg:~$ dexit
wooledg@wooledg:~$ 

(The next keystroke after that removes the terminal.)



Re: Feature request - ganged file test switches

2014-08-13 Thread Ken Irving
On Wed, Aug 13, 2014 at 12:16:52PM -0400, Steve Simmons wrote:
> 
> On Aug 12, 2014, at 4:36 PM, Chet Ramey  wrote:
> 
> > On 8/9/14, 7:07 AM, Steve Simmons wrote:
> > 
> >> It would be nice to have ganged file test switches. As an example, to test 
> >> that a directory exists and is properly accessible one could do
> >> 
> >>  if [[ -d foo ]] && [[ -r foo ]] && [[ -x foo ]] ; then . . .
> >> 
> >> but
> >> 
> >>  if [[ -drx foo ]] ; then . . .
> >> 
> >> is a lot easier.
> > 
> > Sure, but it's only syntactic sugar.
> 
> Knew that going in :-). Other discussion points out how limited it is;
> I'm perfectly happy pulling back. My thoughts on how to do this more
> flexibly boil down to the capabilities gnu find has w/r/t file types
> and modes. Unfortunately we have a few systems which lack gnu find
> and are "vendor supported appliances" (eyeroll) and we're unable to
> add new software beyond simple scripts. Which also means that any new
> bash feature would probably be unavailable for years, so it's not like
> this is a big loss.
>
> If others have no interest in this syntactic sugar I see little point
> to adding it; a broader and more flexible solution is just to use find
> as above.

I like the idea, but switch negation would need to be supported, and
I don't think that's been covered sufficiently.  Using ! as a switch
modifier might be possible, and I like it, but would then also apply to
single filetest switches, e.g., -!e foo would be the same as ! -e foo.
Maybe that's possible, but it seems a fairly major addition to the syntax.

Using caps for switch negation is pretty common, but the filetest switches
already use some uppercase values, so I don't think that's possible in
this case.

I'm a little confused about the 'before' example:

if [[ -d foo ]] && [[ -r foo ]] && [[ -x foo ]] ; then . . .

I thought that && could be used reliably within the [[ ]] construct,
including short-circuiting the tests, so this could be:

if [[ -d foo && -r foo && -x foo ]] ; then . . .

I don't see how the bundled switces could be ambiguous, so must be 
missing something.

Ken



Re: change in behavior starting with bash-4.3_p14 and $@ in [[...]]

2014-08-13 Thread Chet Ramey
On 8/13/14, 10:09 AM, Greg Wooledge wrote:
> On Wed, Aug 13, 2014 at 09:47:51AM -0400, Chet Ramey wrote:
>> On 8/12/14, 11:05 PM, Mike Frysinger wrote:
>>> foo=(0 0 0); [[ -z ${foo[@]#0} ]]; echo $?
> 
>> Word splitting is
>> suppressed inside [[, so the array expands to a single word ("0 0 0"), the
>> 0s are removed, leaving "  "
> 
> That doesn't sound right.  Either you get a single word and remove the
> leading 0 only, or you remove the 0s from each array element first,
> and then get a single word by concatenating what's left.

Not quite.  The expansion happens before word splitting, and the @ causes
the result to be treated specially.  This is the basic set of steps:

1.  The foo[@] is expanded into a list (0 0 0), noting that the @ was
present so the result can be handled accordingly.

2.  The #0 is applied to each member of the list, as it would be in any
other context.  If you were to echo the results here, kind of like
you did below, you would get three empty words.

3.  The results are `glued' together as if $* were used, due to the
presence of `@', so the three empty words are separated by two spaces.

4.  The two spaces remain because word splitting is not performed; the
empty words disappear.

> The code that Mike posted is pretty wonky in the first place.  I don't
> understand what its intent is.  (It's expanding an array into a list of
> words in a context where you can't have a list... and then checking the
> string length of that list-not-list as if it were a string... what?)

Yeah, I assume it's a quick way to test whether all elements of an array
are identical.

> 
> The right-hand side of an assignment also suppresses word splitting, so
> I tried this:
> 
> imadev:~$ foo=(0 0 0); x=${foo[@]#0}
> imadev:~$ echo "<$x>"
> <>
> imadev:~$ foo=(0 0 0); x="${foo[@]#0}"
> imadev:~$ echo "<$x>"
> <  >
> imadev:~$ echo $BASH_VERSION
> 4.3.22(5)-release
> 
> Looks like the second one expanded to a list of empty words and then
> concatenated them together with spaces.  I have no idea what the first
> one did, or why it's different.

It looks like a bug.  I assume it's because bash treats "$@" and $@
(and their array equivalents) differently, even in contexts where word
splitting is not going to happen.  I will have to look at it.

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: Cannot trap INT in child of an interactive shell

2014-08-13 Thread Chet Ramey
On 8/13/14, 12:08 PM, Greg Wooledge wrote:
> Bash 4.3.22, HP-UX.
> 
> imadev:~$ child() { trap - INT; trap 'echo I got an INT; trap - INT; kill 
> -INT $
> BASHPID' INT; while true; do sleep 1; done; }; child &
> [1] 19116
> imadev:~$ kill -INT 19116
> imadev:~$ kill -INT 19116
> imadev:~$ kill -TERM 19116
> [1]+  Terminated  child
> 
> The manual says:
> 
>   Non-builtin commands run by bash have signal handlers set to the
>   values inherited by the shell from its parent.  When job control is
>   not in effect, asynchronous commands ignore SIGINT and SIGQUIT in
>   addition to these inherited handlers.
> 
> And yes, turning on job control magically makes it work:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_11:

"When a command is in an asynchronous list, it shall inherit from the
shell a signal action of ignored (SIG_IGN) for the SIGQUIT and SIGINT
signals, and may inherit a signal mask in which SIGQUIT and SIGINT are
blocked. Otherwise, the signal actions and signal mask inherited by the
command shall be the same as those inherited by the shell from its parent
unless a signal action is modified by the trap special built-in (see
trap)."

The idea is to protect asynchronous children from keyboard-generated
signals, since all child processes belong to the same process group as
the shell, and keyboard signals are sent to all processes in the terminal's
process group.

When job control is active, all child jobs are in separate process groups,
so this is not an issue and doesn't need to happen.

That, combined with this:

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_28

"Signals that were ignored on entry to a non-interactive shell cannot be
trapped or reset, although no error need be reported when attempting to do
so."

means that bash doesn't allow signals that were ignored when it started,
whether that is a separate invocation or a forked child running a command,
to be changed via `trap'.  There has been some discussion on the Posix
list about exactly what "on entry" means, but nothing conclusive.

(And, FWIW, ksh93 behaves as bash does in this regard.)

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: Script with set -m launched from interactive shell makes all ancestor shells die

2014-08-13 Thread Chet Ramey
On 8/13/14, 12:42 PM, Greg Wooledge wrote:
> This was tested on bash 4.3.22 (HP-UX) and bash 4.2.37 (Linux).
> 
> Create a script named foo with the following content:
> 
> #!/bin/bash
> set -m
> while sleep 1; do :; done
> 
> Make it executable, and type
> 
> ./foo &
> 
> at an interactive shell.  You get your shell prompt back.  You can press
> Enter as many times as you like.  But if you press any key other than
> Enter, the entire terminal window goes away.

I haven't looked at this yet, but here's what I bet is happening: turning
on job control with set -m causes several things to happen: the shell
creates a new process group and becomes the process group leader, sets the
terminal's process group to its own process group, and creates children in
their own process group.

Now that the terminal is no longer in the parent shell's process group,
reads return EOF (or -1/EIO), and the parent shell exits.

The details may not be exactly this, but this is the general set of events.

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: Feature request - ganged file test switches

2014-08-13 Thread Steve Simmons
On Aug 13, 2014, at 2:31 PM, Ken Irving  wrote:

> I like the idea, but switch negation would need to be supported, and
> I don't think that's been covered sufficiently.  Using ! as a switch
> modifier might be possible, and I like it, but would then also apply to
> single filetest switches, e.g., -!e foo would be the same as ! -e foo.
> Maybe that's possible, but it seems a fairly major addition to the syntax.

Agree on all.


> I'm a little confused about the 'before' example:
> 
>if [[ -d foo ]] && [[ -r foo ]] && [[ -x foo ]] ; then . . .
> 
> I thought that && could be used reliably within the [[ ]] construct,
> including short-circuiting the tests, so this could be:
> 
>if [[ -d foo && -r foo && -x foo ]] ; then . . .
> 
> I don't see how the bundled switces could be ambiguous, so must be 
> missing something.

Both forms work, which I didn't expect. Learn something new every day; thanks.