This is done easily using awk
. First print out the name, then pipe the output to awk again (this time using space as the file separator).
awk -F "|" '{print $2}' extract.txt | awk -F " " '{print $2 "," $1}'
It's not that much that there's no output as that it's coming in chunks.
Like many programs, when its output is no longer a terminal, cut
buffers its output. That is, it only writes data when it has accumulated a buffer-full of it. Typically, something like 4 or 8 KiB though YMMV.
You can easily verify it by comparing:
(echo foo; sleep 1; echo bar) | cut -c2-
With:
(echo foo; sleep 1; echo bar) | cut -c2- | cat
In the first case, cut
outputs oo\n
and then ar\n
one second later, while in the second case, cut outputs oo\nar\n
after 1 seconds, that is when it sees the end of its input and flushes its output upon exit.
In your case, since stdin is nc
, it would only see the end of its input when the connection is closed, so it would only start outputting anything after it has accumulated 4KiB worth of data to write.
To work around that, several approaches are possible.
On GNU or FreeBSD systems, you can use the stdbuf
utility that can tweak the buffering behaviour of some commands (it doesn't work for all as it uses a LD_PRELOAD hack to pre-configure the stdio buffering behaviour).
... | stdbuf -oL cut -d, -f15,16 | cat
would tell cut
to do a line-based buffering on its stdout.
some commands like GNU grep
have options to affect their buffering. (--line-buffered
in the case of GNU grep
).
you can use a pseudo-tty wrapper to force the stdout of a command to be a terminal. However most of those solutions have some drawbacks and limitations. The unbuffer
expect
script for instance, often mentioned to address this kind of problem has a number of bugs for instance.
One that doesn't work too bad is when using socat
as:
... | socat -u 'exec:"cut -d, -f15,16",pty,raw' -
You can replace your text utility with a higher-level text processing tool that has support for unbuffered output.
GNU awk
for instance has a fflush()
function to flush its output. So your cut -d, -f15,16
could be written:
awk -F, -vOFS=, '{print $15,$16;fflush()}'
if your awk
lacks the fflush()
function, you can use system("")
instead. That's normally the command to execute a command. Here, we would be executing an empty command, but actually using it for the fact that awk
flushes its stdout before running the command.
or you can use perl
:
perl -F, -lane 'BEGIN{$,=",";$|=1} print @F[14..15]'
Best Answer
With
-d " "
, the field separator is one (and only one) space character. Contrary to the shell word splitting,cut
doesn't treat space any different than any other character. Socut -d " " -f2
returns""
inroot 19
, just like it would return""
forcut -d: -f2
inroot:::19
.You'd need to either squeeze the blanks to transform any sequence of space into one space:
Or use
awk
where in its default spitting mode, it doesn't use a separator but splits into the list of sequences of non-blank characters:In this case though, you may want to use:
Or at least:
To match against the arguments only.