bug-bash
[Top][All Lists]
Advanced

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

Re: Backslash mysteriously disappears in command expansion when unescapi


From: Charles-Henri Gros
Subject: Re: Backslash mysteriously disappears in command expansion when unescaping would reference an existing file
Date: Wed, 22 May 2019 19:14:44 +0000

On 5/22/19 10:47 AM, Greg Wooledge wrote:
> On Wed, May 22, 2019 at 05:34:22PM +0000, Charles-Henri Gros wrote:
>> On 5/22/19 5:43 AM, Greg Wooledge wrote:
>>> Standard disclaimers apply.  Stop using unquoted variables and these
>>> bugs will stop affecting you.  Nevertheless, Chet may want to take a
>>> peek.
>> What unquoted variables? Are you talking about the "$()" expansion?
> Yes.  I used a variable instead of a command substitution to make it
> easier to reproduce the problem.  Both have the same behavior in this
> case.

That's what I find a bit surprising (but shells are complicated, so
maybe this is right. All I know is that the code used to work). I didn't
think glob expansions applied to command expansions.

All I want here is word split (which is why I can't use quotes)

>
>> The problem I'm trying to solve is to iterate over regex-escaped file
>> names obtained from a "find" command. I don't know how to make this
>> work. It works with other versions of bash and with other shells.
> First step: do not "regex-escape" them, whatever that means.  Just use
> the actual filenames as printed by find -print0.
>
>> The original is closer to something like this:
>>
>> for file in $(find ... | sed 's/\$/\\$/g'); do grep -e "$file"
>> someinput; done
> Yeah, that's just the wrong approach.  It's also the first thing on
> the BashPitfalls page[1] (for a good reason).
>
> You have two choices here:
>
> 1) Use find -exec.
>
>    find ... -exec grep -e someinput /dev/null {} +
>
> 2) Use find -print0 and a bash while read loop.  (NOT a for loop.)
>
>    find ... -print0 |
>    while IFS= read -rd '' file; do
>       something "$file"
>    done
>
>    (A variant of this uses < <() instead of a pipeline, so that the while
>    loop runs in the main shell and variable assignments can persist.)
>
> Since you only show a simple grep as your action, find -exec is a better
> choice for this problem.  (Assuming you didn't fatally misrepresent the
> problem.)  Calling grep once for every file would be inefficient.

I don't think I fatally misrepresented the problem, however I do think
that you fatally misunderstood it (FWIW I know about -print0 and xargs -0)

The file name is the regex (argument to "-e"), not the file "grep"
reads. I want to check that some text file contains a reference to a file.

But it looks like this would work:

for file in $(find ...); do grep -e "$(echo -n "$file" | sed 's/\$/\\$/g')" 
someinput; done


-- 
Charles-Henri Gros




reply via email to

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