You could do the following using some implementations of find
and xargs
like this.
$ find . -type f -print0 | xargs -r0 ./myscript
or, standardly, just find
:
$ find . -type f -exec ./myscript {} +
Example
Say I have the following sample directory.
$ tree
.
|-- dir1
| `-- a\ file1.txt
|-- dir2
| `-- a\ file2.txt
|-- dir3
| `-- a\ file3.txt
`-- myscript
3 directories, 4 files
Now let's say I have this for ./myscript
.
#!/bin/bash
for i in "$@"; do
echo "file: $i"
done
Now when I run the following command.
$ find . -type f -print0 | xargs -r0 ./myscript
file: ./dir2/a file2.txt
file: ./dir3/a file3.txt
file: ./dir1/a file1.txt
file: ./myscript
Or when I use the 2nd form like so:
$ find . -type f -exec ./myscript {} +
file: ./dir2/a file2.txt
file: ./dir3/a file3.txt
file: ./dir1/a file1.txt
file: ./myscript
Details
find + xargs
The above 2 methods, though looking different, are essentially the same. The first is taking the output from find, splitting it using NULLs (\0
) via the -print0
switch to find. The xargs -0
is specifically designed to take input that's split using NULLs. That non-standard syntax was introduced by GNU find
and xargs
but is also found nowadays in a few others like most recent BSDs. The -r
option is required to avoid calling myscript
if find
finds nothing with GNU find
but not with BSDs.
NOTE: This entire approach hinges on the fact that you'll never pass a string that's exceedingly long. If it is, then a 2nd invocation of ./myscript
will get kicked off with the remainder of subsequent results from find.
find with +
That's the standard way (though it was only added relatively recently (2005) to the GNU implementation of find
). The ability to do what we're doing with xargs
is literally built into find
. So find
will find a list of files and then pass that list as as many arguments as can fit to the command specified after -exec
(note that {}
can only be last just before +
in this case), running the commands several times if needed.
Why no quoting?
In the first example we're taking a shortcut by completely avoiding the issues with the quoting, by using NULLs to separate the arguments. When xargs
is given this list it's instructed to split on the NULLs effectively protecting our individual command atoms.
In the second example we're keeping the results internal to find
and so it knows what each file atom is, and will guarantee to handle them appropriately, thereby avoiding the whoie business of quoting them.
Maximum size of command line?
This question comes up from time to time so as a bonus I'm adding it to this answer, mainly so I can find it in the future. You can use xargs
to see what the environment's limit like so:
$ xargs --show-limits
Your environment variables take up 4791 bytes
POSIX upper limit on argument length (this system): 2090313
POSIX smallest allowable upper limit on argument length (all systems): 4096
Maximum length of command we could actually use: 2085522
Size of command buffer we are actually using: 131072
This bug is mentioned on the mailing list.
The fix is to edit the file git-completion.zsh
and remove the -Q
option from compadd
, in in __gitcomp_file
.
--- i/contrib/completion/git-completion.zsh
+++ w/contrib/completion/git-completion.zsh
@@ -90,7 +90,7 @@ __gitcomp_file ()
local IFS=$'\n'
compset -P '*[=:]'
- compadd -Q -p "${2-}" -f -- ${=1} && _ret=0
+ compadd -p "${2-}" -f -- ${=1} && _ret=0
}
__git_zsh_bash_func ()
This file is installed from the contrib/completion
directory, and its path may vary with your package manager. If you installed with homebrew on macOS, it's located in /usr/local/Cellar/git/2.10.2/share/zsh/site-functions
.
Best Answer
Believe it might be better to use
compgen
instead offind
in this case.You probably already have a completion script with system. Try e.g.
On Debian variants this is probably:
where you find e.g.
_filedir
. So the simplest way then would be something in the direction of:If that is not an option this could be a starter:
A variant using
find
could be something in direction of this:Also note that
printf
in Bash has a%q
option. So to generate quoted strings this is an option to play with:Also not that file names can have newline characters in which a lot of this will break. Have not found a way to use
\0
withcompgen
.