I have to find recursively inside a bash script. Since I can invoke the bash script from anywhere, I am forced to use the absolute path. Sometimes the absolute path can get very long, and the output get's tedious in the following:

#!/usr/bin/env bash
find /long/absolute/path -type f | sort

So I did:

#!/usr/bin/env bash
find /long/absolute/path -type f | xargs -L 1 -I @ echo $(basename @) | sort

But this doesn't gives the basename. Could you please find out where I am going wrong?


You went wrong in two ways:

  1. You're passing semi-arbitrary filenames from find through two pipes -- to xargs and then on to sort. Use null-terminated -print0 from find, if you're able, or embed the actions inside -exec, as maulinglawns demonstrated.

  2. IF you had filenames that never contained any characters from $IFS, your command would still fail because you've asked xargs to execute echo with a command substitution; that command substitution asks basename to output the base name of @, which probably doesn't exist. Closer would have been:

    find /long/absolute/path -type f | xargs -L 1 -I @ basename @ | sort

... as that would have allowed xargs to interpolate the filenames as arguments to basename.

  • Thanks for the answer. Why do you suggest that probably @ didn't exists? The above script file in the question does print out the filenames although with the absolute path, implying that @ is not blank – Porcupine Sep 17 '18 at 19:15
  • 2
    when you used command substitution, it ran before xargs filled in @, so basename was looking for a file named exactly @ – Jeff Schaller Sep 17 '18 at 19:24

This works for me:

find /some/long/path/ -type f -exec basename {} \;| sort
  • This works. Is \; necessary? Any idea why mine didn't work? – Porcupine Sep 17 '18 at 18:46
  • 1
    Yes, it is necessary. Without it you get find: missing argument to '-exec'. I don't know why your variant didn't work, I rarely use xargs myself. – maulinglawns Sep 17 '18 at 18:48
  • 1
    be aware of arbitrary filenames being passed from find through the pipe to sort --- touch $'/some/long/path/foo\nbar' ---> bar on one line, foo on the next. – Jeff Schaller Sep 17 '18 at 18:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.