find -exec question...

find -exec question...

am 19.01.2008 17:46:48 von mandrews58

i am wondering if it is possible to use pattern matching like ${var
%pattern} in a find -exec clause?

There are other ways to accomplish this of course, but as an example
i'd like to strip off the extension to all matches.

find -name "*.txt" -exec echo ${'{}'%.txt} \; will result in a bad
substitution error.

Re: find -exec question...

am 19.01.2008 18:35:57 von James Michael Fultz

* mandrews58 :
> i am wondering if it is possible to use pattern matching like ${var
> %pattern} in a find -exec clause?
>
> There are other ways to accomplish this of course, but as an example
> i'd like to strip off the extension to all matches.
>
> find -name "*.txt" -exec echo ${'{}'%.txt} \; will result in a bad
> substitution error.

Shell expansions are unavailable since find executes the command
directly. Invoking a shell is one solution:

find . -name '*.txt' -exec sh -c 'f={}; echo ${f%.txt}' \;

However, it is not safe for filenames containing shell metacharacters.
Another solution would be to strip the extensions with sed:

find . -name '*.txt' -print | sed 's/\.txt$//'

Also, a Zsh solution:

for f (**/*.txt) echo ${f%.txt}

--
James Michael Fultz
Remove this part when replying ^^^^^^^^

Re: find -exec question...

am 20.01.2008 07:12:48 von Stephane CHAZELAS

On Sat, 19 Jan 2008 11:35:57 -0600, James Michael Fultz wrote:
> * mandrews58 :
>> i am wondering if it is possible to use pattern matching like ${var
>> %pattern} in a find -exec clause?
>>
>> There are other ways to accomplish this of course, but as an example
>> i'd like to strip off the extension to all matches.
>>
>> find -name "*.txt" -exec echo ${'{}'%.txt} \; will result in a bad
>> substitution error.
>
> Shell expansions are unavailable since find executes the command
> directly. Invoking a shell is one solution:
>
> find . -name '*.txt' -exec sh -c 'f={}; echo ${f%.txt}' \;
>
> However, it is not safe for filenames containing shell metacharacters.

and is not portable nor standard.

The correct way is to do it:

find . -name '*.txt' -exec sh -c '
file=$1
base=${file%.txt}
printf "%s\n" "$base"' inline {} \;

Make sure you have the POSIX sh first in $PATH (do
PATH=$(getconf PATH):$PATH if need be).

> find . -name '*.txt' -exec sh -c 'f={}; echo ${f%.txt}' \;
> Another solution would be to strip the extensions with sed:
>
> find . -name '*.txt' -print | sed 's/\.txt$//'
>
> Also, a Zsh solution:
>
> for f (**/*.txt) echo ${f%.txt}

Not strictly equivalent as it ommits hidden files and dirs and
sorts the list of files and builds the whole list of files
before displaying it. It also displays an error if there's not
matching file.

{: **/*.txt(DNe{'print -r -- $REPLY:r; false'})}

is a bit of a hack but is pretty close to the find equivalent.

for f (**/*.txt(DNoN)) print -r -- $f:r

is probably good enough though.

Or:

print -rl -- **/*.txt(DoN:r)

--
Stephane

Re: find -exec question...

am 21.01.2008 01:25:35 von mandrews58

>
> The correct way is to do it:
>
> find . -name '*.txt' -exec sh -c '
> file=$1
> base=${file%.txt}
> printf "%s\n" "$base"' inline {} \;
>

I've searched man pages and haven't found an explanation for the
purpose of the inline in "printf "%s\n" "$base"' inline {} \;"
removing the inline results in output of blank lines. where is a
reference to use of "inline {}"?

TIA -mark

Re: find -exec question...

am 21.01.2008 01:54:43 von Icarus Sparry

On Sun, 20 Jan 2008 16:25:35 -0800, mandrews58 wrote:


>> The correct way is to do it:
>>
>> find . -name '*.txt' -exec sh -c '
>> file=$1
>> base=${file%.txt}
>> printf "%s\n" "$base"' inline {} \;
>>
>>
> I've searched man pages and haven't found an explanation for the purpose
> of the inline in "printf "%s\n" "$base"' inline {} \;" removing the
> inline results in output of blank lines. where is a reference to use of
> "inline {}"?
>
> TIA -mark

There are 2 questions here. The first is easy, what is the meaning of {}?
This is filled in by find to be the name of the file that is being tested.

The other question is "what are the meanings of additional parameters to
sh -c, after the first one"?

The answer is that if there are any, then they are given to $0, $1, $2
etc. This is pretty unexpected, as if you are not using -c, extra
parameters are stored in $1, $2, $3 etc and $0 is given the name of the
program or the name of the shell.

So the "inline" here is just somthing to give to $0, so the filename ends
up in $1 as one would expect.