[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: find improvement wish
From: |
Chun Yip Wong |
Subject: |
Re: find improvement wish |
Date: |
Mon, 8 Feb 2021 12:17:04 +0800 |
Thanks for detailed explanation,
在 2021年2月8日 週一 11:47,Bob Proulx <bob@proulx.com> 寫道:
> Chun Yip Wong wrote:
> > I prefer using find with script in this way: find $dir $pattern.where
> > pattern=" -name *.sh ! -name *.txt ... etc."
>
> There is a problem with insufficiently quoted shell file glob meta
> characters in that pattern. That's a problem unrelated to find.
>
> > The built findutils version is 4.7. it fails to work with such message
> >
> > find: paths must precede expression: 'test.sh'
> > find: possible unquoted pattern after predicate '-name'
>
> And there is a warning about "possible unquoted pattern" but since we
> can see the pattern we know that yes the pattern is not quoted and
> that is an error of the command line.
>
> > I know when there are multiple files, such as a.txt b.txt c.txt, find .
> > -name *.txt will cause such messages and solve with quoted the '*.txt'
> > It is more convenient to define a pattern and no need to quote all
> > extensions one by one, line by line using scripts.
>
> The "*" file glob character is a shell meta-character. The shell
> being your command line shell. One of bash, ksh, zsh, or possibly
> even tcsh, csh, or possibly another. The shell is not find. The
> shell reads the command and expands shell file glob patterns like
> "*.txt" into files that match. After the shell has expanded these
> characters then the resulting multiple arguments are passed to the
> command. In this case the command find.
>
> In order to observe this expansion the "echo" command is most easily
> used. If one uses echo they can see how the patterns are expanded.
> Or if there is no match then how it is not expanded. It is a data
> dependent expansion based upon whether any files exist that match the
> pattern or not. Which is why any characters that happen to be shell
> metacharacters must be quoted to prevent this expansion. For use in
> the fine -name option it is not desired to have them expanded and
> therefore this must be prevented.
>
> $ touch a.txt b.txt c.txt
> $ pattern=" -name *.sh ! -name *.txt"
> $ echo find $dir $pattern
> find -name *.sh ! -name a.txt b.txt c.txt
>
> And here we see that -name *.txt is expanded to be -name a.txt b.txt
> c.txt when -name uses exactly one argument. The "-name a.txt" is read
> and then b.txt and c.txt is extra and not part of -name.
>
> The expansion of the shell is useful for other commands that are not
> find to use. For example they are useful with ls.
>
> $ echo ls -log *.txt
> ls -log a.txt b.txt c.txt
>
> $ ls -log *.txt
> -rw-rw-r-- 1 0 Feb 7 20:36 a.txt
> -rw-rw-r-- 1 0 Feb 7 20:36 b.txt
> -rw-rw-r-- 1 0 Feb 7 20:36 c.txt
>
> That is useful for ls and other commands but it is not useful for find
> and therefore those file glob characters, and other shell meta
> characters, must be quoted to prevent this expension.
>
> > I prefer using find with script in this way: find $dir $pattern.where
> > pattern=" -name *.sh ! -name *.txt ... etc."
>
> Quote the arguments. Since this is in a double quoted string then it
> is convenient to use single quotes in the string.
>
> pattern=" -name '*.sh' ! -name '*.txt' ... etc."
>
> And then the result will be this. First a reminder of the problem
> case.
>
> $ pattern=" -name *.sh ! -name *.txt"; echo find $dir $pattern
> find -name *.sh ! -name a.txt b.txt c.txt
>
> And then we fix it by adding quotes.
>
> $ pattern=" -name '*.sh' ! -name '*.txt'"; echo find $dir $pattern
> find -name '*.sh' ! -name '*.txt'
>
> As some background information the "*" is called a file glob character
> and the expansion is called globbing (see "man glob") because the "*"
> matches a "glob" of file name characters. A glob being a bunch of
> characters. It's a very casual word idiom for a bunch of characters.
> This dates back to the earliest implementation of Unix.
>
> Bob
>