Deutsch   English   Français   Italiano  
<v0ig4l$96sa$1@dont-email.me>

View for Bookmarking (what is this?)
Look up another Usenet article

Path: ...!weretis.net!feeder9.news.weretis.net!feeder8.news.weretis.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail
From: Lawrence D'Oliveiro <ldo@nz.invalid>
Newsgroups: comp.unix.shell,comp.os.linux.misc
Subject: Executing Shell Pipelines with =?UTF-8?B?4oCcZmluZCAtZXhlY+KAnQ==?=
Date: Sat, 27 Apr 2024 09:22:29 -0000 (UTC)
Organization: A noiseless patient Spider
Lines: 50
Message-ID: <v0ig4l$96sa$1@dont-email.me>
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Injection-Date: Sat, 27 Apr 2024 11:22:29 +0200 (CEST)
Injection-Info: dont-email.me; posting-host="9e4fadc78fe91d749786c6f98d388f78";
	logging-data="301962"; mail-complaints-to="abuse@eternal-september.org";	posting-account="U2FsdGVkX1/Uo8uYWy/PgFi5d7cwq+gX"
User-Agent: Pan/0.155 (Kherson; fc5a80b8)
Cancel-Lock: sha1:NRZ6PUHePAC5BqfQy3CZXsUyats=
Bytes: 3351

The “find” command <https://manpages.debian.org/1/find.en.html> offers
a great variety of ways to filter out files. And if none of them is
quite good enough, you can use the “-exec” option to execute an
arbitrary command.

Unfortunately, it must be an arbitrary *single* command.

For example, I wanted to identify .blend files created by Blender
versions after 3.4. I have a command called “blendfile_version”
<https://gitlab.com/ldo/blender-useful/> which will output some basic
version information about a .blend file in JSON format. From this,
it’s easy enough to extract the version string with

    blendfile_version «blendfile» | jq -r .version

and then filter out older versions with

    test $(blendfile_version «blendfile» | jq -r .version) -gt 304

But this command cannot be used as is with -exec! That is, if I try

    find . -name \*.blend -exec test $(blendfile_version {} | jq -r .version) -gt 304 \; -print

that won’t work, because -exec will not feed the command to a shell to
handle the command substitution, pipelining etc.

However, you can explicitly invoke a shell and give it a one-shot
command with “sh -c”. While the command string must be a single word,
it is possible to have multiple argument words following this command.
So if the command happens to be “eval”, that gives you your ability to
feed the separate words of the -exec command to the shell, thus:

    find . -name \*.blend -exec sh -c 'eval "${@}"' \
        sh test \$\( blendfile_version {} \| jq -r .version \) -gt 304 \; -print

This works, but it assumes that the find command will only substitute
the “{}” sequence with the file name if it occurs as a separate word.
In fact, GNU find will perform this substitution even if the sequence
occurs as part of a word. This allows the -exec command to be
simplified somewhat, by getting rid of the “eval” stage:

    find . -name \*.blend -exec \
        sh -c '[ $(blendfile_version {} | jq -r .version ) \> 304 ]' \; \
        -print

And there we have it. Some commands have a “quiet” option, where you
give them a criterion to match, and they return an exit status
indicating success/failure to match (e.g. “grep -q”). Having this may
make use with find just a little bit easier, but as you can see, it’s
not strictly necessary.