16

i am looking for a way to sort the results of find returning a number of directories correctly for further processing in a bash script. since filenames can't contain the NULL (\0) character i thought this would make a great delimiter for the results being piped to sort.

so this is what i would expect to work as described:

find ./ -maxdepth 1 -type d -iname 'xyz?' -print0 | sort -t $'\0'

but sadly i got the compaint sort: empty tab

looking around for a explanation a came across a question leading to a similar result that the op described as working fine (see lucas comment of apr 26th). in my case (using GNU sort v 7.4) this is seems different.

i also checked the output of find by piping into od -c but this only shows that the resulting folders are separated by NULL as expected.

has anybody here come across a similar scenario and possibly found a solution or explanation why \0 seem to be an impossible delimiter for sort?

looking forward to you answers...

edit: note that the find-command is used as an example here, a simpler way to test/illustrate this could be echo "g\0u\0b\0k" | sort -t $'\0'

codeforester
  • 39,467
  • 16
  • 112
  • 140
antiplex
  • 938
  • 2
  • 12
  • 17
  • 1
    does your version of sort not support the -z option? I am on version 5.93 and that supports -z for null terminated entries. – borrible Jul 03 '11 at 16:29
  • oh well, yes it does! i really should understand the difference between line and field separator! thanks a lot! – antiplex Jul 03 '11 at 16:42

3 Answers3

18

-t is the field separator. If you want to use \0 as the line separator then you need to use -z.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358
3

For further processing in a Bash script see, for example:

Capturing output of find . -print0 into a bash array

# cf. http://mywiki.wooledge.org/BashFAQ/020
unset a i
while IFS='' read -r -d $'\0' dir; do
   a[i++]="$dir"        # or however you want to process each directory
done < <(find ./ -maxdepth 1 -type d -iname 'xyz?' -print0 | LC_ALL=C sort -z)

printf '%s\n' "${#a[@]}"
printf '%s\n' "${a[@]}"

# btw, you may use printf to add zero bytes
printf '%c\000' g u b k | sort -z | tr '\0' ' '
printf '%s\000' g1 u2 b3 k4 | sort -z | tr '\0' ' '
Community
  • 1
  • 1
jeff
  • 31
  • 1
  • if checked out @jeff 's link to bashFAQ (very interesting!) and found the explanation for `IFS=''` in the while loop being necessary to not accidentially trim whitespace. so `IFS=` `IFS=''` and `IFS=$'\0'` would represent the same thing here: NUL – antiplex Jul 04 '11 at 20:26
1

Use the -z option to sort zero-terminated data sets:

find ./ -maxdepth 1 -type d -iname 'xyz?' -print0 | sort -z | tr '\0' '\n'
hans
  • 11
  • 1
  • 1
    converting NULL into a newline at the end is an interesting idea but would in my opinion rise the same issues with filenames including a newline as if newline was chosen as a delimiter right from the start... – antiplex Jul 03 '11 at 17:08