1

I am trying to implement this solution:

Make xargs handle filenames that contain spaces

to cat several files that are to be selected using find.

Therefore, I have tried to implement the BSD solution provided in that post, but if I do:

$ find "/tmp/database"  -name "FOO 03-11*" 
/tmp/database/01/FOO 03-11.txt
/tmp/database/03/FOO 03-11.txt
/tmp/database/02/FOO 03-11.txt
/tmp/database/05/FOO 03-11.txt
/tmp/database/04/FOO 03-11.txt

$ find "/tmp/database"  -name "FOO 03-11*" | sort 
/tmp/database/01/FOO 03-11.txt
/tmp/database/02/FOO 03-11.txt
/tmp/database/03/FOO 03-11.txt
/tmp/database/04/FOO 03-11.txt
/tmp/database/05/FOO 03-11.txt

$ find "/tmp/database"  -name "FOO 03-11*" | sort | xargs -0
/tmp/database/01/FOO 03-11.txt
/tmp/database/02/FOO 03-11.txt
/tmp/database/03/FOO 03-11.txt
/tmp/database/04/FOO 03-11.txt
/tmp/database/05/FOO 03-11.txt

$ find "/tmp/database"  -name "FOO 03-11*" | sort | xargs -0 cat
cat: /tmp/database/01/FOO 03-11.txt
/tmp/database/02/FOO 03-11.txt
/tmp/database/03/FOO 03-11.txt
/tmp/database/04/FOO 03-11.txt
/tmp/database/05/FOO 03-11.txt
: No such file or directory
$ 

I still can not get the cat command working. What is missing from the accepted answer of the provided post to get cat working with xargs -0?

I am using FreeBSD 12 and its shell /bin/sh which as far as I know is POSIX.

I would -clearly wrongly- expect this find/sort/xargs/cat sequence to output the contents of the file as in:

$ cat "/tmp/database/01/FOO 03-11.txt"
CONTENT OF FILE /tmp/database/01/FOO 03-11.txt
$ cat "/tmp/database/02/FOO 03-11.txt"
CONTENT OF FILE /tmp/database/02/FOO 03-11.txt
$ cat "/tmp/database/03/FOO 03-11.txt"
CONTENT OF FILE /tmp/database/03/FOO 03-11.txt
$ cat "/tmp/database/04/FOO 03-11.txt"
CONTENT OF FILE /tmp/database/04/FOO 03-11.txt
$ cat "/tmp/database/05/FOO 03-11.txt"
CONTENT OF FILE /tmp/database/05/FOO 03-11.txt

So the expected output would be:

$ find "/tmp/database"  -name "FOO 03-11*" | sort | xargs -0 cat
CONTENT OF FILE /tmp/database/01/FOO 03-11.txt
CONTENT OF FILE /tmp/database/02/FOO 03-11.txt
CONTENT OF FILE /tmp/database/03/FOO 03-11.txt
CONTENT OF FILE /tmp/database/04/FOO 03-11.txt
CONTENT OF FILE /tmp/database/05/FOO 03-11.txt
M.E.
  • 4,955
  • 4
  • 49
  • 128
  • It works - there is no such directory. `xargs` properly passed the input to `cat` - it works, correctly, and then `cat` tells you that there is no such directory - also, most probably, correctly. Did you expect something else? Why? What do you think `-0` means? – KamilCuk May 30 '21 at 11:09
  • The files are under `/tmp/database/0x` and I want to cat them. I have edited the question so the expected output is more clear. – M.E. May 30 '21 at 11:14
  • If you can exclude the possibility that you may have one day so many files that you would get an _arglist too long_ error if you feed them all together into a single `cat`, you could also do a `cat $(find ...| sort)`. – user1934428 May 31 '21 at 07:21
  • I tried and that solution does not work with files with spaces in the name, at least not in `/bin/sh` in FreeBSD `$ cat $(find "/tmp/database" -name "FOO 03-11*" | sort) cat: /tmp/database/01/FOO: No such file or directory ...` – M.E. May 31 '21 at 10:29

1 Answers1

4

FreeBSD xargs does not support -d as suggested in a deleted answer, but the answer was useful as it clarified -0 usage and gives the hint to handle the new line characters as delimiters, so an inclusion of tr to turn \n into \0 can do the trick for FreeBSD:

$ find "/tmp/database"  -name "FOO 03-11*" | sort | tr '\n' '\0' | xargs -0 cat
CONTENT OF FILE /tmp/database/01/FOO 03-11.txt
CONTENT OF FILE /tmp/database/02/FOO 03-11.txt
CONTENT OF FILE /tmp/database/03/FOO 03-11.txt
CONTENT OF FILE /tmp/database/04/FOO 03-11.txt
CONTENT OF FILE /tmp/database/05/FOO 03-11.txt

As a side note, in GNU Linux it could be used -d '\n':

find "/tmp/database"  -name "FOO 03-11*" | sort | xargs -d '\n' cat
M.E.
  • 4,955
  • 4
  • 49
  • 128
  • 4
    According to online manuals `find '/tmp/database' -name 'FOO 03-11*' -print0 | sort -z | xargs -0 cat` should work on FreeBSD. The one in your answer breaks if a file contains `'`, `"`, ```\```, or a line break in its name, this one doesn't. – oguz ismail May 30 '21 at 13:51
  • Thanks I confirm that it actually works in FreeBSD, I was not aware on `-z` and `-print0` arguments. In this particular case I do not intend to deal with files containing `'`,`"` or \ (which are arguably bad character choices for a filename) but it is an useful clarification. – M.E. May 30 '21 at 20:34