Post History
Say I have some Bash function my-func, that expects a filename and does some processing on the corresponding file. For demonstration purposes, my-func() { cat "$1"; } If I want to apply that fu...
#3: Post edited
- Say I have some Bash function `my-func`, that expects a filename and does some processing on the corresponding file. For demonstration purposes,
- ```
- my-func() { cat "$1"; }
- ```
- If I want to apply that function to all the text files in the current directory, I eventually figured out that I can do:
- ```
- export -f my-func
find . -name '*.txt' -print0 | xargs -0 bash -c 'my-func "$@"' _- ```
- Now suppose I want to generalize this process. I want to make another function, where I can pass `my-func` (or some other function name, or command, or alias - the key feature is that *this will expect only one argument*, a filename forwarded from `xargs`) followed by the arguments that `find` should use to choose the files to process.
- That is, I'd like to be able to define `apply-to-files`, such that I can call e.g. `apply-to-files my-func . -name '*.txt'` and have it do the right thing (in this case, `cat` each file found by `find . -name '*.txt'`).
- What does that look like? My first thought is
- ```
- apply-to-files() {
find "${@:2}" -print0 | xargs -0 bash -c '$1 "$@"' _- }
- ```
but that doesn't seem right. I need a way to disambiguate that the `$1` refers to the arguments of `apply-to-files`, but the second `$@` refers to the single-element list of arguments passed to the worker function (named in `$1`, invoked by `xargs`). I'm also getting lost in the quoting by this point.
- Say I have some Bash function `my-func`, that expects a filename and does some processing on the corresponding file. For demonstration purposes,
- ```
- my-func() { cat "$1"; }
- ```
- If I want to apply that function to all the text files in the current directory, I eventually figured out that I can do:
- ```
- export -f my-func
- find . -name '*.txt' -print0 | xargs -0 -I{} bash -c 'my-func "{}"' _
- ```
- Now suppose I want to generalize this process. I want to make another function, where I can pass `my-func` (or some other function name, or command, or alias - the key feature is that *this will expect only one argument*, a filename forwarded from `xargs`) followed by the arguments that `find` should use to choose the files to process.
- That is, I'd like to be able to define `apply-to-files`, such that I can call e.g. `apply-to-files my-func . -name '*.txt'` and have it do the right thing (in this case, `cat` each file found by `find . -name '*.txt'`).
- What does that look like? My first thought is
- ```
- apply-to-files() {
- find "${@:2}" -print0 | xargs -0 -I{} bash -c '$1 "{}"' _
- }
- ```
- but that doesn't seem right. I'm getting lost in the quoting, and I'm confused about which arguments are coming from where. And indeed, it doesn't seem to work; it appears to be treating the filenames from `find` as the executable name to run, causing a bunch of "Permission denied" errors. Finally, this setup is assuming that the named operation will be a Bash function; I'd prefer if it could work transparently with (executables, aliases, shell builtins, ...) as well.
#1: Initial revision
Higher-order functions in Bash?
Say I have some Bash function `my-func`, that expects a filename and does some processing on the corresponding file. For demonstration purposes, ``` my-func() { cat "$1"; } ``` If I want to apply that function to all the text files in the current directory, I eventually figured out that I can do: ``` export -f my-func find . -name '*.txt' -print0 | xargs -0 bash -c 'my-func "$@"' _ ``` Now suppose I want to generalize this process. I want to make another function, where I can pass `my-func` (or some other function name, or command, or alias - the key feature is that *this will expect only one argument*, a filename forwarded from `xargs`) followed by the arguments that `find` should use to choose the files to process. That is, I'd like to be able to define `apply-to-files`, such that I can call e.g. `apply-to-files my-func . -name '*.txt'` and have it do the right thing (in this case, `cat` each file found by `find . -name '*.txt'`). What does that look like? My first thought is ``` apply-to-files() { find "${@:2}" -print0 | xargs -0 bash -c '$1 "$@"' _ } ``` but that doesn't seem right. I need a way to disambiguate that the `$1` refers to the arguments of `apply-to-files`, but the second `$@` refers to the single-element list of arguments passed to the worker function (named in `$1`, invoked by `xargs`). I'm also getting lost in the quoting by this point.