zsh-users
 help / color / mirror / code / Atom feed
* unmatched '
@ 2018-03-09 17:50 Ray Andrews
  2018-03-09 20:23 ` Bart Schaefer
  0 siblings, 1 reply; 7+ messages in thread
From: Ray Andrews @ 2018-03-09 17:50 UTC (permalink / raw)
  To: Zsh Users

I have a function that lists all directories matching a nesting set of 
strings:

$ c etc systemd system

... the list is culled by matching each string in turn.  It works fine 
except that:

$ c etc

(eval):1: unmatched '

... but that's the one and only directory that throws that error.  I've 
tested dozens of directories and combinations and all are fine except 
'etc'. I suspect this abomination:

/etc/DSHR's Blog: Using the official Linux overlayfs_files

... God knows why that's permitted, but I'm thinking that the single 
quote is doing the obvious thing as far as 'eval' in concerned.  Can I 
prevent that?  Or, if it must be an error, can I get eval to ignore it 
somehow? The offending line is this:

baz=(`eval print -l $bar $grepstring`)

... I want to sent the output of printing '$bar' after it's been piped 
through the chain of greps that are built up and saved in the 
'$grepstring' variable, and save that filtered and colored result in 
'$baz'.  Apart from the above, it works perfectly.  I'm betting there's 
a flag ${(flag)bar} that fixes it, i.e. forcing " DSHR's " to be 
literal.  Otherwise I will excoriate the offending directories.  Work of 
the Devil.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: unmatched '
  2018-03-09 17:50 unmatched ' Ray Andrews
@ 2018-03-09 20:23 ` Bart Schaefer
  2018-03-09 22:45   ` Ray Andrews
  0 siblings, 1 reply; 7+ messages in thread
From: Bart Schaefer @ 2018-03-09 20:23 UTC (permalink / raw)
  To: Ray Andrews; +Cc: Zsh Users

On Fri, Mar 9, 2018 at 9:50 AM, Ray Andrews <rayandrews@eastlink.ca> wrote:
>
> $ c etc
>
> (eval):1: unmatched '
>
> I suspect this abomination:
>
> /etc/DSHR's Blog: Using the official Linux overlayfs_files
>
> ... God knows why that's permitted, but I'm thinking that the single quote
> is doing the obvious thing as far as 'eval' in concerned.  Can I prevent
> that?  Or, if it must be an error, can I get eval to ignore it somehow? The
> offending line is this:
>
> baz=(`eval print -l $bar $grepstring`)

You really should never do this with "eval".  Consider what happens if the
file name is /etc/Why you should never `rm -rf /`

(Obligatory warning:  DO NOT TRY THAT AT HOME.)

Why are you putting stuff like that file in /etc/ in the first place?
It's not meant to be a scratch or documentation directory, it's
supposed to contain system-wide configuration files.
https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard

> ... I want to sent the output of printing '$bar' after it's been piped
> through the chain of greps that are built up and saved in the '$grepstring'

If $bar is a file name with spaces in it, `eval print -l $bar` is
going to split the name up on the spaces and write one "word" of the
file name on each line.  Is that actually what you intend?  Otherwise
unless $bar is an array, you don't need the -l option of print,
because you're always printing just one line anyway.

If $bar is a file name that begins with a hyphen, "print" is going to
try to interpret that as options.

Based on your description there must be a leading "|" in $grepstring.
Don't do that.

Assuming you've carefully sanitized $grepstring to avoid gotchas like
unintentional `...` or $(...) substitutions, the closest you should
ever get to what you're doing is

baz=( `print -lr -- "${bar[@]}" | eval "$grepstring"` )

There's probably a better way to do your cascade of greps, too, such
as building a file with one pattern per line and running a single
"grep -f patternfile", but you haven't provided sufficient context.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: unmatched '
  2018-03-09 20:23 ` Bart Schaefer
@ 2018-03-09 22:45   ` Ray Andrews
  2018-03-09 23:12     ` Ray Andrews
  2018-03-10  3:20     ` Aaron Schrab
  0 siblings, 2 replies; 7+ messages in thread
From: Ray Andrews @ 2018-03-09 22:45 UTC (permalink / raw)
  To: zsh-users

On 09/03/18 12:23 PM, Bart Schaefer wrote:
> You really should never do this with "eval". Consider what happens if the
> file name is /etc/Why you should never `rm -rf /`
>
> (Obligatory warning:  DO NOT TRY THAT AT HOME.)
I probably have a lot of improper constructions here, I use the first 
thing that seems to work, and later I repent of various sins as they 
become apparent.  How would I best do that sort of thing?
> Why are you putting stuff like that file in /etc/ in the first place?

Heck, not me!  That's stock Debian, I'd not create a directory like that 
on pain of damnation.  Debian should not allow it either, IMHO.

> If $bar is a file name with spaces in it, 

$bar will start with a list of directories as originally output by 
'find', so whatever my code, it has to handle whatever 'find' might find.
> Based on your description there must be a leading "|" in $grepstring.
> Don't do that.
Yeah:

     ccolor=33      # Start with yellow, then blue, magenta, cyan.
     for file in "$@"; do
         # We colorize the already selected lines here:
         grepstring="$grepstring | GREP_COLOR='01;'"$ccolor" grep $wwild 
$ccase --color=always \"$file\""
         (( ccolor++ )) # Next color.
     done

... so I'm filtering and colorizing however many arguments there are to 
the command, so each iteration must (?) begin with the pipe.  And the 
final string:

     bar=(`eval "find -H -O3  / -warn  -type d -ipath \"*$1*\"" 
$grepstring`)
> Assuming you've carefully sanitized $grepstring to avoid gotchas like
> unintentional `...` or $(...) substitutions, the closest you should
> ever get to what you're doing is
>
> baz=( `print -lr -- "${bar[@]}" | eval "$grepstring"` )
>
> There's probably a better way to do your cascade of greps, too, such
> as building a file with one pattern per line and running a single
> "grep -f patternfile", but you haven't provided sufficient context.
>
The $grepstring itself can't have any surprises (famous last words) but 
the entire construction is of course suspect.  I see you're shrinking 
the target of eval to the minimum, that seems sensible on first 
principals but I can't think of a way to get the first pipe outside of 
$grepstring.  The thing is just to turn a string into a command because 
the only way I know to create flexible commands is by way of strings.

Anyway, is there no way of putting a global protection on nasty 
characters inside the list of directories?  I'm sure I did read about 
that, but there's so much to remember.

BTW I started doing this sort of cascading colorization with a very 
similar function I use to explore the history.  I can refine the search 
with as many strings as I want, and they all show up with different 
colors, which is even useful, not just eye candy. The final array gets 
fed to Sebastian's 'n_list' for selection. Quite indispensable to me.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: unmatched '
  2018-03-09 22:45   ` Ray Andrews
@ 2018-03-09 23:12     ` Ray Andrews
  2018-03-10  3:20     ` Aaron Schrab
  1 sibling, 0 replies; 7+ messages in thread
From: Ray Andrews @ 2018-03-09 23:12 UTC (permalink / raw)
  To: zsh-users

On 09/03/18 02:45 PM, Ray Andrews wrote:

> baz=( `print -lr -- "${bar[@]}" | eval "$grepstring"` )
     baz=(`eval print -lr -- ${(q)bar} $grepstring`)

That works, " (q) " was the thing I was trying to  remember.   It's in 
the scrolls, and my Coptic is getting better ;-))

    baz=( `print -lr -- "${bar[@]}" eval "$grepstring"` )   << pipe 
within $grepstring as per previous logic

... didn't work , but maybe there is a better way?


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: unmatched '
  2018-03-09 22:45   ` Ray Andrews
  2018-03-09 23:12     ` Ray Andrews
@ 2018-03-10  3:20     ` Aaron Schrab
  2018-03-10  3:51       ` Ray Andrews
  1 sibling, 1 reply; 7+ messages in thread
From: Aaron Schrab @ 2018-03-10  3:20 UTC (permalink / raw)
  To: Ray Andrews; +Cc: zsh-users

At 14:45 -0800 09 Mar 2018, Ray Andrews <rayandrews@eastlink.ca> wrote:
>>Why are you putting stuff like that file in /etc/ in the first place?
>
>Heck, not me!  That's stock Debian, I'd not create a directory like 
>that on pain of damnation.  Debian should not allow it either, IMHO.

No, that file is not included in any Debian package:

https://packages.debian.org/search?searchon=contents&keywords=DSHR&mode=filename&suite=stable&arch=any

>    ccolor=33      # Start with yellow, then blue, magenta, cyan.
>    for file in "$@"; do
>        # We colorize the already selected lines here:
>        grepstring="$grepstring | GREP_COLOR='01;'"$ccolor" grep 
>$wwild $ccase --color=always \"$file\""
>        (( ccolor++ )) # Next color.
>    done
>
>... so I'm filtering and colorizing however many arguments there are 
>to the command, so each iteration must (?) begin with the pipe.  And 
>the final string:

Perhaps something like the following? This doesn't include the doing the 
find(1), instead it's designed to get the text to search on STDIN.  It 
also doesn't use the $wwild or $ccase variables, which I didn't see 
defined anywhere. But that would be easy to add.

No use of eval here. Besides being safer, that also tends to be more 
readable; although the use of recursion here cuts down on that 
improvement.

Despite having zsh on the #! line, this would work with bash as well.

#!/bin/zsh -u
# Multi-color grep

__mcgrep() {
  local color=$1; shift
  local pattern="$1"; shift

  if [[ $# = 0 ]]; then
    # No more patterns, just pass through the input
    cat
  else
    __mcgrep $((color + 1)) "$@"
  fi |
    GREP_COLOR="01;$color" grep --color=always "$pattern"
}

# Start with yellow, then blue, magenta, cyan.
__mcgrep 33 "$@"


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: unmatched '
  2018-03-10  3:20     ` Aaron Schrab
@ 2018-03-10  3:51       ` Ray Andrews
  2018-03-10 17:40         ` Ray Andrews
  0 siblings, 1 reply; 7+ messages in thread
From: Ray Andrews @ 2018-03-10  3:51 UTC (permalink / raw)
  To: zsh-users

On 09/03/18 07:20 PM, Aaron Schrab wrote:
>
> No, that file is not included in any Debian package:
So I've since discovered.  God knows where it came from, it's nothing of 
mine, that's for sure.  Apologies to Debian for the suggestion.  I've 
since killed it.
>
>
>
> Perhaps something like the following? This doesn't include the doing 
> the find(1), instead it's designed to get the text to search on 
> STDIN.  It also doesn't use the $wwild or $ccase variables, which I 
> didn't see defined anywhere. But that would be easy to add.
>
> No use of eval here. Besides being safer, that also tends to be more 
> readable; although the use of recursion here cuts down on that 
> improvement.
>
> Despite having zsh on the #! line, this would work with bash as well.
>
> #!/bin/zsh -u
> # Multi-color grep
>
> __mcgrep() {
>  local color=$1; shift
>  local pattern="$1"; shift
>
>  if [[ $# = 0 ]]; then
>    # No more patterns, just pass through the input
>    cat
>  else
>    __mcgrep $((color + 1)) "$@"
>  fi |
>    GREP_COLOR="01;$color" grep --color=always "$pattern"
> }
>
> # Start with yellow, then blue, magenta, cyan.
> __mcgrep 33 "$@"
>
Thanks, that's interesting, I'll experiment with it tomorrow.



^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: unmatched '
  2018-03-10  3:51       ` Ray Andrews
@ 2018-03-10 17:40         ` Ray Andrews
  0 siblings, 0 replies; 7+ messages in thread
From: Ray Andrews @ 2018-03-10 17:40 UTC (permalink / raw)
  To: zsh-users

On 09/03/18 07:51 PM, Ray Andrews wrote:
> On 09/03/18 07:20 PM, Aaron Schrab wrote:
>>
>> #!/bin/zsh -u
>> # Multi-color grep
>>
>> __mcgrep() {
>>  local color=$1; shift
>>  local pattern="$1"; shift
>>
>>  if [[ $# = 0 ]]; then
>>    # No more patterns, just pass through the input
>>    cat
>>  else
>>    __mcgrep $((color + 1)) "$@"
>>  fi |
>>    GREP_COLOR="01;$color" grep --color=always "$pattern"
>> }
>>
>> # Start with yellow, then blue, magenta, cyan.
>> __mcgrep 33 "$@"
>>
> Thanks, that's interesting, I'll experiment with it tomorrow.
>
>
>
That sure got me thinking.  At the very least I can drop 'eval' by looping:

     for file in "$@"; do
         foo=( `print -l $foo | GREP_COLOR='01;'$ccolor grep 
--color=always $file` )
         bar=( `print -l $bar | GREP_COLOR='01;'$ccolor grep 
--color=always $file` )
         (( ccolor++ )) # Next color.
     done

... it seems that one pipe at a time is fine, so rather than create the 
chain of pipes ahead of time, and try to pass it via $grepstring, if I 
just loop, everything is fine.  My entire function ends up 600 bytes 
shorter and the whole thing is much easier to read.



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-03-10 18:10 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-09 17:50 unmatched ' Ray Andrews
2018-03-09 20:23 ` Bart Schaefer
2018-03-09 22:45   ` Ray Andrews
2018-03-09 23:12     ` Ray Andrews
2018-03-10  3:20     ` Aaron Schrab
2018-03-10  3:51       ` Ray Andrews
2018-03-10 17:40         ` Ray Andrews

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).