commit:     187db88dfd631e9e10bc2e5e710f96a64d01e169
Author:     Göktürk Yüksek <gokturk <AT> gentoo <DOT> org>
AuthorDate: Sat Oct 29 16:27:05 2016 +0000
Commit:     Göktürk Yüksek <gokturk <AT> gentoo <DOT> org>
CommitDate: Mon Oct 31 01:09:00 2016 +0000
URL:        https://gitweb.gentoo.org/proj/devmanual.git/commit/?id=187db88d

tools-reference/find: encourage the while read loop with '-print0'

The "funky while read loop" has problems coping with file names
containing special characters. Improve it by using the '-print0'
option that uses the NUL character to delimit the output lines, which
can be processed safely by the while read loop by adjusting the
delimiter settings.

As for whether supplying $'\0' is an undocumented feature or not, see:
http://lists.gnu.org/archive/html/help-bash/2016-10/msg00039.html

Suggested-By: David Seifert <soap <AT> gentoo.org>

 tools-reference/find/text.xml | 31 ++++++++++++++++++++-----------
 1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/tools-reference/find/text.xml b/tools-reference/find/text.xml
index 4172128..8601a51 100644
--- a/tools-reference/find/text.xml
+++ b/tools-reference/find/text.xml
@@ -112,6 +112,15 @@ Useful rules include:
     </ti>
     <ti>no, GNU and FBSD</ti>
   </tr>
+  <tr>
+    <ti><c>-print0</c></ti>
+    <ti>
+      Separate file names by a NUL character instead of a newline in
+      the output. This is useful for guarding against files which may
+      include a newline in their names.
+    </ti>
+    <ti>no, GNU and FBSD</ti>
+  </tr>
 </table>
 
 <note>
@@ -121,30 +130,30 @@ ebuild context for those EAPIs.
 
 <p>
 By default, <c>find</c> will echo a list of matching files to the
-standard output. This can be used in a <c>while</c> loop:
+standard output separated by newlines. It can be combined with a
+<c>for</c> loop for a small number of files with no weird characters
+and spaces in their names:
 </p>
 
 <codesample lang="ebuild">
-while read f ; do
+for f in $(find "${S}" -type f) ; do
     einfo "Doing unholy things to ${f}"
-done &lt; &lt;(find "${S}" -type f)
+done
 </codesample>
 
 <p>
-Or a <c>for</c> loop (for small numbers of files):
+The above loop may cause issues with files containing special
+characters in their names. A better way is to run <c>find</c> with the
+<c>-print0</c> option in a <c>while</c> loop (note the options passed
+to <c>while</c> and <c>read</c> for changing the delimiter):
 </p>
 
 <codesample lang="ebuild">
-for f in $(find "${S}" -type f) ; do
+while IFS="" read -d $'\0' -r f ; do
     einfo "Calling down holy vengance upon ${f}"
-done
+done &lt; &lt;(find "${S}" -type f -print0)
 </codesample>
 
-<warning>
-In both cases, files with weird characters or spaces in their names
-may cause serious problems.
-</warning>
-
 <p>
 As an alternative you can use the <c>-exec</c> argument. Be careful
 with escaping to ensure that <c>bash</c> doesn't gobble up the special

Reply via email to