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.