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,
  • do you always execute two commands, the output format is always the same ? – mazs May 3 '16 at 15:36
  • I not want to run the ssh twice and inserting the output to variable – yael May 3 '16 at 15:42
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/,$//'
  • 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 May 3 '16 at 16:02
  • @yael the awk solution in the updated answer will work for any number of output lines. – terdon May 3 '16 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 May 3 '16 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 May 3 '16 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. – Dominik Gebhart May 3 '16 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
  • 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 May 3 '16 at 16:01
  • in this case you change the if [[ counter -eq 1 ]] to if [[ counter -eq 2 ]] – mazs May 3 '16 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 May 3 '16 at 16:13
  • corrected script to use instead of $line the quoted variable "$line", this way you'll probably have the right output – mazs May 3 '16 at 16:15
  • also , my previous comment is wrong, you have to correct if [[ counter -eq 1 ]] to if [[ counter -le 2 ]] – mazs May 3 '16 at 16:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.