Executing Shell Pipelines with “find -exec”

Liste des GroupesRevenir à cu shell 
Sujet : Executing Shell Pipelines with “find -exec”
De : ldo (at) *nospam* nz.invalid (Lawrence D'Oliveiro)
Groupes : comp.unix.shell comp.os.linux.misc
Date : 27. Apr 2024, 11:22:29
Autres entêtes
Organisation : A noiseless patient Spider
Message-ID : <v0ig4l$96sa$1@dont-email.me>
User-Agent : Pan/0.155 (Kherson; fc5a80b8)
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.

Date Sujet#  Auteur
27 Apr 24 * Executing Shell Pipelines with “find -exec”8Lawrence D'Oliveiro
27 Apr 24 +* Re: Executing Shell Pipelines with “find -exec”6Christian Weisgerber
27 Apr 24 i+* Re: Executing Shell Pipelines with ?find? _-exec?4Robert Heller
27 Apr 24 ii`* Re: Executing Shell Pipelines with ?find? _-exec?3Kaz Kylheku
27 Apr 24 ii `* Re: Executing Shell Pipelines with ?find? _-exec?2Robert Heller
5 May 24 ii  `- Re: Executing Shell Pipelines with ?find? _-exec?1Friedhelm Waitzmann
28 Apr 24 i`- Re: Executing Shell Pipelines with “find -exec”1Lawrence D'Oliveiro
5 May 24 `- Re: Executing Shell Pipelines with “find -exec”1Friedhelm Waitzmann

Haut de la page

Les messages affichés proviennent d'usenet.

NewsPortal