How to edit a list of generated files whose names contain spaces

Since you are in Bash,

#!/bin/bash
readarray -d '' -t files < <(find path -type f -print0)
vi -- "${files[@]}"

Replace find path -type f -print0 with your actual pipeline.

Although your files have no newlines, the support for such filenames has been added by user glenn jackman.

To use tabs instead of buffers for vi, add the -p flag: vi -p ....


If the pipeline was not required, you could straighforwardly use the -exec option:

find path -type f -exec vi -- {} +

Unfortunately this does not work when mycommand is an editor because although xargs can assemble the set of files to edit, stdin is already taken up from the pipeline and I can't see a way to run an editor in-place.

That way is documented in the manual page for the GNU Findutils xargs:

   -o, --open-tty
          Reopen stdin as /dev/tty in the child process  before  executing
          the  command.  This is useful if you want xargs to run an inter‐
          active application.

So that you could use

find . -name 'pattern' -print0 | xargs -0o vim

However, it is a newer feature. I don't see it in an older system that has xargs 4.4.2; I see it on Ubuntu 18, which has xargs 4.7.0.

Now xargs may not have had the -o option ten years ago, but Bash process substitution existed ten years ago, and xargs has the -a option to read from a file instead of standard input.

So the problem is solvable without xargs -o like this:

xargs -0 -a <(find . -name 'pattern' -print0) vim

Because xargs is reading from (what it thinks is) a file that it received as an argument, it has left standard input alone.


From the comments I get something similar like this is your command:

find -type f -mtime +14 -mtime -22 -iname '*.xml' | while IFS= read -f x; do xmlstarlet sel -T -t -v '//magicElement' -n "$x" | grep -q magicValue && echo "$x"; done 

Instead of piping to a while - loop you could use -exec sh -c '...' to filter files:

find -type f -mtime +14 -mtime -22 -iname '*.xml' \
  -exec sh -c 'xmlstarlet sel -T -t -v "//magicElement" "$1" | grep -q magicValue' find-sh {} \; \
  -exec vi -- {} +

Try:

Consider three files:

.
├── a:<magicElement>magicValue</magicElement>
├── b:<magicElement>magicValue</magicElement>
└── c:<magicElement>someOtherValue</magicElement>

$ find . -type f \
  -exec sh -c 'xmlstarlet sel -T -t -v "//magicElement" "$1" | grep -q magicValue' find-sh {} \; \
  -exec echo vi -- {} +

Output:

vi -- ./a ./b