Re: using exec to close a fd in a var crashes bash

2023-08-22 Thread Martin D Kealey
On Wed, 23 Aug 2023, 12:20 Greg Wooledge,  wrote:

> > echo Hi {X}>/dev/null
> > ls -l "/proc/$$/fd/$X"
>
> That's a really strange example.  I wonder what would lead someone to
> write that particular redirection.


Oh I merely wanted to point out that the redirection persists beyond the
echo command. It's basically the same as your example:

The thing I was testing was in response to this question, which was posed
> as an exercise:
>
> Swap stderr and stdout of a shell command.
>
> I gave […]
>
> cmd {fd}>&1 1>&2 2>&$fd {fd}>&-
>
> [which] does *not* close the temporary file
> descriptor


Well, it closes at as far as cmd is concerned, but not as far as the Shell
is concerned.

I would expect {fd}>&- to exactly undo {fd}>/path (or {fd}>&$otherfd), so
they should either both be local to the command, or both apply to the shell.

Indeed quite I'm perplexed as to why it wasn't designed this way to begin
with.

I'm also mystified as to why they persist, in stark contrast to other
redirections, but that's comparatively less important. (I recall there was
some discussion about the variable persisting, but I didn't think it
implied the fd itself would persist.)

This seems like a clear example of an experimental feature that should have
been indicated as such in the release notes, and only enabled when
explicitly chosen at build time (e.g. ./configure
--enable-all-experimental-features-without-warnings). Chopping and changing
behaviour in "permanent" releases creates a maintenance nightmare.

-Martin


Re: using exec to close a fd in a var crashes bash

2023-08-22 Thread Greg Wooledge
On Wed, Aug 23, 2023 at 12:05:42PM +1000, Martin D Kealey wrote:
> On Wed, 23 Aug 2023, 05:29 Greg Wooledge,  wrote:
> 
> > Excuse me now, while I go and close several open FDs in the shell where
> > I tested something the other day, which I had no idea were left open.
> >
> 
> It's even worse than that; try:
> 
> echo Hi {X}>/dev/null
> ls -l "/proc/$$/fd/$X"

That's a really strange example.  I wonder what would lead someone to
write that particular redirection.  What's the intended outcome, in
terms of the variable X and the state of file descriptors?  If you
simply want to discard output, there's no reason I can think of to
use {X}>/dev/null instead of simply >/dev/null.

The thing I was testing was in response to this question, which was
posed as an exercise:

Swap stderr and stdout of a shell command.

I gave two answers:

cmd 3>&1 1>&2 2>&3 3>&-

and

cmd {fd}>&1 1>&2 2>&$fd {fd}>&-

As it turns out, the second one does *not* close the temporary file
descriptor, so each time I ran the function while testing, an extra
file descriptor was left open.

But this variant *does* close it:

cmd {fd}>&1 1>&2 2>&$fd
exec {fd}>&-

I find this incredibly confusing.



Re: using exec to close a fd in a var crashes bash

2023-08-22 Thread Martin D Kealey
On Wed, 23 Aug 2023, 05:29 Greg Wooledge,  wrote:

> Excuse me now, while I go and close several open FDs in the shell where
> I tested something the other day, which I had no idea were left open.
>

It's even worse than that; try:

echo Hi {X}>/dev/null
ls -l "/proc/$$/fd/$X"

-Martin

>


Re: using exec to close a fd in a var crashes bash

2023-08-22 Thread Greg Wooledge
On Tue, Aug 22, 2023 at 02:59:14PM -0400, Dale R. Worley wrote:
> The "{var}>..." mechanism *assigns* to $var, rather than
> taking its existing value.

... oh.  Well, today I learned something.

Excuse me now, while I go and close several open FDs in the shell where
I tested something the other day, which I had no idea were left open.



Re: using exec to close a fd in a var crashes bash

2023-08-22 Thread Chet Ramey

On 8/22/23 2:59 PM, Dale R. Worley wrote:

Is there any way to write a redirection "Redirect the fd whose number is
in $FOO to file /foo/bar?"  OK, you can write 'bash -c "..."' and
assemble a command string however you want.  But is there a direct way
to write it?  The "{var}>..." mechanism *assigns* to $var, rather than
taking its existing value.


If you want an extra round of word expansion, use eval.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/




Re: using exec to close a fd in a var crashes bash

2023-08-22 Thread Dale R. Worley
Is there any way to write a redirection "Redirect the fd whose number is
in $FOO to file /foo/bar?"  OK, you can write 'bash -c "..."' and
assemble a command string however you want.  But is there a direct way
to write it?  The "{var}>..." mechanism *assigns* to $var, rather than
taking its existing value.

Dale



Re: read -E with read -d in completion function

2023-08-22 Thread Chet Ramey

On 8/21/23 5:50 PM, Grisha Levit wrote:

The new read -E option is a nice addition.
I think it's not unreasonable for a completion function to itself invoke
`read' (with a file or pipe as input, not a tty) and this mostly works out
fine, unless the -d option is used since the builtin stores the delimiter
arg in a static variable:


Thanks for the suggestion. This looks reasonable.

--
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/




Error handling with nofork command substitution

2023-08-22 Thread jm
Hi,

With the new funsub syntax ${ cmd;} and ${| cmd;} that encourages
returning the value of $REPLY to the caller, I've been thinking about
an idiomatic way of doing error handling and propagation that may
call for a new shell option or new type of funsub.

So the idea is natural, when a function encounters an error condition
it "raises" an error message by setting it in $REPLY and returning a
non-zero exit code, when there's no error it simply sets $REPLY to a
return value and returns a zero exit code.

For example:

function div {
  local -i x="$1" y="$2"
  if ((y==0)); then
REPLY='CANNOT DIVIDE BY 0'
return 100
  else
REPLY=$((x/y))
  fi
}

function bin {
  local -i x="$1"
  case "$x" in
  (*[!01]*)
REPLY='NOT BINARY NUMBER: '"$x"
return 200
  ;;
  (*)
REPLY=$((2#$x))
  esac
}

Now, "catching" an error can be done with an if or case statement
plus ${| cmd;} and propagation can be done by simply returning the
exit code (which the caller has to again catch with REPLY=${| cmd;}).
For example:

function main {
  REPLY=${| bin 10102; }
  case $? in
  (0) ;;
  (*)
local code=$?
echo "Error Message: [$REPLY], Exit Code: [$code]"
return $code
  esac

  echo "There was no error! Decimal: $REPLY"
}

This is good but verbose for propagation, to address this languages
like Rust or Swift introduced a `?` operator that simply returns back
the code and message to the caller. We could emulate this in Bash
like this:

function ? {
  if REPLY=${| "$@"; }; then
printf -- '%s' "$REPLY"
  else
return $?
  fi
}

function calculation_steps {
  local -i ratio bi
  ratio=${ ? div 10 5  ;} || return $?   # ratio = div(10,5)?;
  bi=${ ? bin "$ratio" ;} || return $?   # bi = bin(ratio)?;
  REPLY="$bi"
}

If there was an error in a step, it gets propagated, if not, we
return the REPLY value.

And here is where I'd like to have like an option or syntactic sugar
that allows me to nest funsubs but returning out of the funsub if an
error was found, simulating `?` method chaining like in those other
languages.

This one doesn't work:

bi=${ ? bin ${ ? div 10 5; } ; } || return $?  # bi = div(10,5)?.bin()?;

This one does work, but is not better than the original:

bi=${
  ratio=${ ? div 10 5; } || return $?
  ? bin "$ratio"
} || return $?

Something like:

bi=${? bin ${? div 10 5; } ; }   # (1)
bi=${ div 10 5 ?| bin ; }# (2)
bi=${
  local -
  set -o errpropagate# (3)
  ? bin ${ ? div 10 5; }
}

I haven't found a solution in pure bash so that's why I'm throwing
new syntax ideas and making this thread; maybe there is and I'd love
to know, otherwise one of these 3 constructions could be implemented
if users find it useful.

(1) is clean, but parsing could be tricky because of $?
(2) would resemble method chaining in other languages but
it's not very idiomatic and probably the hardest to implement
(3) is probably easier to implement, no new syntax, but users
would still have to know and define their `?` propagation function

I'd also like some feedback on this error handling strategy.
Is there a better way? Does it have pitfalls?

Thanks, José