2

the following command print the two values in one ssh shut

ssh test01 "hostname && cat  /etc/sysconfig/rhn/rhnsd "


test01
INTERVAL=240

but how to change the syntax in order to print the following format: (CSV) ,

 test01,INTERVAL=240

.

I try to ( but not as expected )

ssh test01 "hostname && cat  /etc/sysconfig/rhn/rhnsd " | awk '{print $1","$2}'


test01,
INTERVAL=240,
2
  • do you always execute two commands, the output format is always the same ?
    – magor
    Commented May 3, 2016 at 15:36
  • I not want to run the ssh twice and inserting the output to variable
    – yael
    Commented May 3, 2016 at 15:42

3 Answers 3

2

All you need to do is parse the command's output and replace the first newline (\n) with a comma. This should work:

ssh test01 "hostname && cat  /etc/sysconfig/rhn/rhnsd " | 
    perl -00pe 's/\n/,/'

Here we're using perl to slurp the entire file into memory (-0) and replace the first \n with a comma. The -p tells perl to print each input "line" (here, a line is the entire file) after running the script given by -e on it.


The reason your awk didn't work is because awk runs the script you give it on every line. Your command prints two lines, both of which only have a single field, $1, so $2 is undefined. Therefore, print $1","$2 is expanded to print "test01""," for the first line and print "INTERVAL=240""," for the second, resulting in

test01,
INTERVAL=240,

A working solution with awk would be:

ssh test01 "hostname && cat  /etc/sysconfig/rhn/rhnsd " | 
    awk '{printf "%s,", $1}' | sed 's/,$//'

That will print the 1st field of each line followed by a comma. The sed command just removes the trailing comma after the last line printed.

To print the whole line instead of just one field, use:

ssh test01 "hostname && cat  /etc/sysconfig/rhn/rhnsd " | 
    awk '{printf "%s,", $0}' | sed 's/,$//'
7
  • excellent - another question how to fit also in case we want to add more then two tasks? for example - "hostname && cat /etc/sysconfig/rhn/rhnsd && cat /etc/redhat-release "
    – yael
    Commented May 3, 2016 at 16:02
  • @yael the awk solution in the updated answer will work for any number of output lines.
    – terdon
    Commented May 3, 2016 at 16:03
  • yes I try it but its print only partial from the third task "cat /etc/redhat-release" , its print Red and not all as Red Hat Enterprise Linux Server release 5.10 (Tikanga)
    – yael
    Commented May 3, 2016 at 16:10
  • @yael see updated answer. However, please don't do this. Your question only mentioned 2 lines of output and you now have multiple lines and also single commands that produce multiple lines. That is quite a different situation. So, either come into /dev/chat or post a new question showing the text you need to parse and the output you want to see.
    – terdon
    Commented May 3, 2016 at 16:14
  • Nice answer, you could add a sed solution along the lines of ssh test01 "hostname && date && hostname" | sed ':a;N;s/\n/, /;ba' which works for multiple lines too, its problematic for higher linecounts though. Commented May 3, 2016 at 19:28
1

Following terdon's advice, im adding an alternative approach using sed, i mainly include it for completeness, however unlike the awk '{printf "%s,", $1}' which aggregates whilst ommitting the newline, with sedwe are actively replacing the newlines, thus it would also fit in when we wanted to replace a different character. It is inefficient though.

The command in question is ssh test01 "date +%m && hostname && cat asdfd.txt && date +%D" | sed ':a;N;s/\n/, /;ba'

The very cryptic sed command :a;N;s/\n/, /;ba is actually quite simple if taken apart.

sedtransforms the input in one single pass (opposed to i.e. ed, however ed usually isnt included by default). The unmodified ssh command returns:

[me@hostname ~]$ ssh test01 "date +%m && hostname && cat asdfd.txt && date +%D"
05
Debian-76-wheezy-64-minimal
a
s
d
f
d
05/04/16

If we add N;s/\n// we get:

[me@hostname ~]$ ssh test01 "date +%m && hostname && cat asdfd.txt && date +%D" | sed 'N;s/\n//'
05Debian-76-wheezy-64-minimal
as
df
d05/04/16

The N appends the next input line into the pattern space, the following s/\n// removes the newline in the pattern space. Thats why we get pairs of lines with removed newlines here.

Now if we want the full input to get sent into the pattern space, we need to loop with help of a label.

[me@hostname ~]$ ssh test01 "date +%m && hostname && cat asdfd.txt && date +%D" | sed ':a;N;s/\n//;ba'
05Debian-76-wheezy-64-minimalasdfd05/04/16

With :a we set a label, with ba we unconditionally jump to the label a.

So what sed ':a;N;s/\n//;ba' does is:

  • Define label a
  • Append next line to pattern space (N)
  • Send pattern space through s/\n//
  • Jump back to a

Once there is no new line for N to append it quits to the end of the script.

To get it CS we just need to change the replacement:

[me@hostname ~]$ ssh test01 "date +%m && hostname && cat asdfd.txt && date +%D" | sed ':a;N;s/\n/, /;ba'
05, Debian-76-wheezy-64-minimal, a, s, d, f, d, 05/04/16

This isnt very efficient, especially for bigger linecount, since the pattern space gets the line appended and sent trought our replacement command for every single line. Would be more efficient to replace before aggregation, but sed can't do that.

This becomes very obvious if we print the pattern space after N appended the next line (Just put a p at the position to get the current pattern space printed). In the following ouput, every 2 lines represetn the current pattern space (because the *newline is still included) - just before the replacement of the newline by s/\n//:

[me@hostname] ssh test01 "date +%m && hostname && cat asdfd.txt && date +%D" | sed ':a;N;p;s/\n/, /;ba'
05
Debian-76-wheezy-64-minimal
05, Debian-76-wheezy-64-minimal
a
05, Debian-76-wheezy-64-minimal, a
s
05, Debian-76-wheezy-64-minimal, a, s
d
05, Debian-76-wheezy-64-minimal, a, s, d
f
05, Debian-76-wheezy-64-minimal, a, s, d, f
d
05, Debian-76-wheezy-64-minimal, a, s, d, f, d
05/04/16
05, Debian-76-wheezy-64-minimal, a, s, d, f, d, 05/04/16
0

For your command this would produce the expected output :

counter=0
ssh test01 "hostname && cat  /etc/sysconfig/rhn/rhnsd " \
  | while read line ; do 
  ((counter++)) 
  if [[ counter -eq 1 ]]; then 
    echo -ne "${line},"
  else
    echo "$line"
  fi
  done
5
  • excellent , but how to fit also in case we want to add more then two tasks as - ssh ub-test01 "hostname && cat /etc/sysconfig/rhn/rhnsd && cat /etc/redhat-release " ??
    – yael
    Commented May 3, 2016 at 16:01
  • in this case you change the if [[ counter -eq 1 ]] to if [[ counter -eq 2 ]]
    – magor
    Commented May 3, 2016 at 16:04
  • I did it but its print that - test01,INTERVAL=240 Red Hat Enterprise Linux Server release 6.7 (Santiago) ( so we have two lines in place on csv line )
    – yael
    Commented May 3, 2016 at 16:13
  • corrected script to use instead of $line the quoted variable "$line", this way you'll probably have the right output
    – magor
    Commented May 3, 2016 at 16:15
  • also , my previous comment is wrong, you have to correct if [[ counter -eq 1 ]] to if [[ counter -le 2 ]]
    – magor
    Commented May 3, 2016 at 16:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .