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 (<m...@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 >