bug-findutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: The xargs -r, --no-run-if-empty Option Is Ignored When a Delimiter I


From: Kurt von Laven
Subject: Re: The xargs -r, --no-run-if-empty Option Is Ignored When a Delimiter Is Passed
Date: Fri, 14 May 2021 19:24:20 -0700

Thank you, Berny. Your explanation was enlightening to a degree I rarely
encounter. Apologies for the erroneous bug report, and thank you for
the quick reply. I confirmed that this issue is specific to <<< by using
pipes instead. I will go forth and use <<< correctly.

Be well,
Kurt

El vie, 14 may 2021 a las 11:53, Bernhard Voelker (<mail@bernhard-voelker.de>)
escribió:

> On 5/11/21 3:58 AM, Kurt von Laven wrote:
> > The following command correctly outputs nothing.
> > xargs --no-run-if-empty -I str echo str <<< ""
> >
> > The following command incorrectly outputs 1 empty line.
> > xargs --no-run-if-empty --delimiter="\n" -I str echo str <<< ""
> >
> > The following command incorrectly outputs 2 empty lines.
> > xargs --no-run-if-empty --null -I str echo str <<< ""
>
> First of all, let's check what the shell syntax '<<<' produces for an
> empty string as argument:
>
>   $ od -tx1z <<< ""
>   0000000 0a                                               >.<
>   0000001
>
> Aha, the shell apparently turns the <<<"" into nothing, but finally
> outputs a newline
> character.  My interpretation of this is that the shell does this for
> POSIX compatibility:
> the receiving tool is supposed to work with text files ... which by
> definition have
> a terminating newline character.
> Also wc(1) tells us that there was 1 line but without a word:
>
>   $ wc  <<< ""
>       1       0       1
>
> Now let's see what is happening in xargs(1) - using the 'strace' tool:
>
>   $ strace -vfe read,write xargs --no-run-if-empty --null -I str echo str
> <<< "" >/dev/null
>   read(3,
> "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`|\2\0\0\0\0\0"..., 832) =
> 832
>   read(0, "\n", 4096)                     = 1
>   read(0, "", 4096)                       = 0
>   strace: Process 31530 attached
>   [pid 31529] read(3, "", 4)              = 0
>   [pid 31530] read(3,
> "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`|\2\0\0\0\0\0"..., 832) =
> 832
>   [pid 31530] write(1, "\n", 1)           = 1
>   [pid 31530] write(1, "\n", 1)           = 1
>   [pid 31530] +++ exited with 0 +++
>   --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=1335,
> si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
>   +++ exited with 0 +++
>
> And here again with my comments in between:
>
>   $ strace -vfe read,write xargs --no-run-if-empty --null -I str echo str
> <<< ""
>   read(3,
> "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`|\2\0\0\0\0\0"..., 832) =
> 832
>
> Ignore, that comes from reading a library.
>
>   read(0, "\n", 4096)                     = 1
>
> xargs reads a partial item - because it hasn't seen neither the delimiter
> '\0' nor EOF until then.
> Therefore it goes for another round ...
>
>   read(0, "", 4096)                       = 0
>
> Now, xargs has hit EOF.
> This means the first and only item is "\n".
> Okay, we have more than Zero items, so it performs the -exec action with
> the -I str replacement:
>
>   strace: Process 31530 attached
>   [pid 31529] read(3, "", 4)              = 0
>
> This read() is in the parent xargs process, and irrelevant for this case.
> It is for error handling - for those who care:
>
> https://git.sv.gnu.org/cgit/findutils.git/tree/xargs/xargs.c?id=11576f4e6a#n1376
>
>   [pid 31530] read(3,
> "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`|\2\0\0\0\0\0"..., 832) =
> 832
>
> ignore again, the child process is reading one of the libraries.
>
>   [pid 31530] write(1, "\n", 1)           = 1
>
> Here, 'echo' outputs the item it got from xargs(1): the newline character.
>
>   [pid 31530] write(1, "\n", 1)           = 1
>
> Here, 'echo' appends the usual newline.
>
>   [pid 31530] +++ exited with 0 +++
>   --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=31530,
> si_uid=1000, si_status=0, si_utime=0, si_stime=0} ---
>   +++ exited with 0 +++
>
> The child process and xargs terminate without error.
>
> With the -t, --verbose option, one can exactly see how echo is invoked (in
> shell-quotation style):
>
>   $ xargs --no-run-if-empty --null -t -I str echo str <<< "" >/dev/null
>   echo ''$'\n'
>
> Therefore, I don't see anything wrong with xargs, and I think it's more a
> matter
> of what a user expects from the shell's <<< operator: it is made for text
> input.
> At least in the manual page of bash(1) on my system, this is documented
> properly:
>
>   Here Strings
>      A variant of here documents, the format is:
>
>         [n]<<<word
>
>     The word undergoes [...], and quote removal.
>     Pathname expansion and word splitting are not performed.
>     The result is supplied as a single string, with a newline appended, to
> the command
> ____^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>     on its standard input (or file descriptor n if n is specified).
>
> Have a nice day,
> Berny
>


reply via email to

[Prev in Thread] Current Thread [Next in Thread]