The following patches the bash shell version 4.1 so that its "read" built-in supports a new "-0" flag. With this patch, "read -0" reads input values delimited by \0, so that "read -0" has the same effect as: IFS='' read -r -d '' Use this like "xargs -0", e.g.: find . -print0 | while read -0 file ... For more information, see: http://www.dwheeler.com/essays/filenames-in-shell.html http://www.dwheeler.com/essays/fixing-unix-linux-filenames.html http://austingroupbugs.net/view.php?id=245 This patch was developed by David A. Wheeler. This patch *itself* is released to the public domain. However, the program it *patches* is under a different license (currently GPLv3), so the combination will be governed by the license of the software it's combined with. (David A. Wheeler, 2010-05-03) ============================================== --- builtins/read.def.orig 2009-10-08 11:35:46.000000000 -0400 +++ builtins/read.def 2010-05-03 21:43:56.000000000 -0400 @@ -1,7 +1,7 @@ This file is read.def, from which is created read.c. It implements the builtin "read" in Bash. -Copyright (C) 1987-2009 Free Software Foundation, Inc. +Copyright (C) 1987-2010 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -22,7 +22,7 @@ $BUILTIN read $FUNCTION read_builtin -$SHORT_DOC read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...] +$SHORT_DOC read [-0ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...] Read a line from the standard input and split it into fields. Reads a single line from the standard input, or from file descriptor FD @@ -35,6 +35,8 @@ If no NAMEs are supplied, the line read is stored in the REPLY variable. Options: + -0 Inputs delimited only by \0, same as IFS='' read -r -d ''. + Use like xargs -0, e.g., find . -print0 | while read -0 file -a array assign the words read to sequential indices of the array variable ARRAY, starting at zero -d delim continue until the first character of DELIM is read, rather @@ -159,6 +161,7 @@ int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2; int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul; int raw, edit, nchars, silent, have_timeout, ignore_delim, fd; + int null_delim; unsigned int tmsec, tmusec; long ival, uval; intmax_t intval; @@ -202,6 +205,7 @@ i = 0; /* Index into the string that we are reading. */ raw = edit = 0; /* Not reading raw input by default. */ + null_delim = 0; silent = 0; arrayname = prompt = (char *)NULL; fd = 0; /* file descriptor to read from */ @@ -217,10 +221,15 @@ ignore_delim = 0; reset_internal_getopt (); - while ((opt = internal_getopt (list, "ersa:d:i:n:p:t:u:N:")) != -1) + while ((opt = internal_getopt (list, "0ersa:d:i:n:p:t:u:N:")) != -1) { switch (opt) { + case '0': + null_delim = 1; + raw = 1; + delim = '\0'; + break; case 'r': raw = 1; break; @@ -315,7 +324,7 @@ if (ifs_chars == 0) /* XXX - shouldn't happen */ ifs_chars = ""; /* If we want to read exactly NCHARS chars, don't split on IFS */ - if (ignore_delim) + if (ignore_delim || null_delim) ifs_chars = ""; for (skip_ctlesc = skip_ctlnul = 0, e = ifs_chars; *e; e++) skip_ctlesc |= *e == CTLESC, skip_ctlnul |= *e == CTLNUL;