lmi
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [lmi] Mustn't expansions precede redirections?


From: Vadim Zeitlin
Subject: Re: [lmi] Mustn't expansions precede redirections?
Date: Tue, 19 May 2020 01:12:04 +0200

On Mon, 18 May 2020 22:41:49 +0000 Greg Chicares <address@hidden> wrote:

GC> TL;DR: in this invocation...
GC> 
GC>   rm --force eraseme*
GC>   touch eraseme.x eraseme.y
GC>   2>&1 foo eraseme* | bar > eraseme_out
GC>            ^^^^^^^^
GC> 
GC> ...can the highlighted expansion of 'eraseme*' on the last line
GC> include 'eraseme_out'?

 Yes, it definitely can with dash. I couldn't reproduce this at first, but
you just need to be persistent:

        $ while true; do echo eraseme* | cat > eraseme.out; cat eraseme.out; rm 
eraseme.out; done

outputs

        eraseme.out eraseme.x eraseme.y

rather quickly, even if the vast majority of outputs doesn't include the
first element. In fact:

        $ while true; do echo eraseme* | cat > eraseme.out; cat eraseme.out; rm 
eraseme.out; done | head -n 1000 | sort | uniq -c
              4 eraseme.out eraseme.x eraseme.y
            996 eraseme.x eraseme.y


 Note that I couldn't reproduce this with zsh:

        % repeat 1000; { echo eraseme* | cat > eraseme.out; cat eraseme.out; rm 
eraseme.out } | sort | uniq -c
           1000 eraseme.x eraseme.y

nor with bash, so it looks once again like a dash-specific weirdness. I'm
not sure whether it's worth investigating it further...

GC> but the evidence below says I'm wrong, so...

 This looks like a strong argument in favour of the first alternative
(unless you're doing highly theoretical computer science).

GC> how can the snippet above be rewritten so that the expansion is
GC> performed before the output file is created?

 Sorry for stating the obvious, but the simplest pragmatic solution would
be to avoid using the same "eraseme" prefix for the output file. Is this
unacceptable for some reason?

 Another workaround would be to use a temporary variable, e.g.

        input_files=`echo eraseme*`
        foo $input_files | bar > eraseme_out

as dash really shouldn't be able to create eraseme_out in the previous line
unless it does speculative read-ahead (which it doesn't).

 Splitting the pipeline and using a temporary file would work too, but
you'd have to call it something other than "eraseme_tmp", and if you're
ready to do this, you could just as well use the first solution.

 I don't see anything clearly better than one of these approaches. Perhaps
I could look into what happens inside dash more closely and discover some
more clever way of avoiding this problem, but, again, I'm not sure if it's
worth it.

 Please let me know if either of the workarounds above is acceptable,
VZ

Attachment: pgpDg9FEeUoTT.pgp
Description: PGP signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]