1

Intro

I am writing a bash script that is being executed from Jenkins Pipeline. Groovy DSL is not a problem for me, I am using bare shell commands.

For every command so far I have been using bash -c and passed over commands I wanted, like below:

ssh -l <user> <host> bash -c "'
     cd /my/path
     ./script.sh param1 param2
     echo $MY_VAR
'"

That works great.


The problem

Now I had a more complicated command:

ls -1t | egrep 'regexp' | tail -n +10 | xargs rm -rf 

Basically listing some directory and deleting all items but for last 10. It works using in bash but it does not with bash -c.

I also tried a for-loop version:

for f in $(ls -1t | egrep 'regexp' | tail -n +10); do rm -rf $f; done;

But it does not work either. I get an error, like:

bash: line 4:
  for f in <actual_item1> <actual_item2> <actual_item3>; do echo <actual_item1>; done;
       No such file or directory

So there is some issue with $ variable resolution. How to overcome this? Or how do I make the piped version work?

Community
  • 1
  • 1
Atais
  • 10,857
  • 6
  • 71
  • 111
  • Please [edit] your question to show the actual ssh command that you're running with quotes and variable references intact. This probably just a matter of getting your quotes right. – Kenster Sep 27 '17 at 13:06
  • it was not the quotes. `bash -c` does not work when passing this pipe (I do not know why), but passing `<< EOF` helps. – Atais Sep 27 '17 at 14:43

4 Answers4

1

You can use here-doc with ssh command to run one or more commands:

ssh $user@$hostname bash -s<<-'EOF'
ls -1t | egrep 'regexp' | tail -n +10 | xargs rm -rf
EOF

It is however not recommended to parse ls command's output, better use find ... -print0 like this:

ssh $user@$hostname bash -s<<-'EOF'
find . -regex '.*regexp' -print0 | tail -zn +10 | xargs -0 rm -rf
EOF
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • This will use my default shell (`ksh`) on the server, so I need to specify the shell. – Atais Sep 27 '17 at 10:25
  • ok `bash -s` should take care of that. Try my updated answer now. – anubhava Sep 27 '17 at 10:30
  • Why do you any shell for this? `ssh $user@$hostname "find . -regex '.*regexp' -print0 | tail -zn +10 | xargs -0 rm -rf"`. – chepner Sep 27 '17 at 11:35
  • Yes @chepner, for these commands `bash` is not needed. Since OP asked specifically to be able to run `bash` I assumed OP is running some more `bash` specific commands on remote host. – anubhava Sep 27 '17 at 11:51
1

At first you dont have to provide +10 to tail -n. by default it takes last 10 lines, if you want use first 10 lines, use head. why do you want use bash -c, it should work if you just provide this command to ssh, or check What is the cleanest way to ssh and run multiple commands in Bash?

darvark
  • 314
  • 3
  • 15
1

It turns out it is partially Jenkins groovy DSL issue, but with help of

I managed to find my way around it.

The solution

    sh("""ssh -o StrictHostKeyChecking=no -l <user> <host> /bin/bash << EOF
        cd /my/dir/;
        ls -1t | egrep 'regexp' | tail -n +10 | xargs rm -rf;
EOF""") 

Comment

The usage of sh plugin is pretty straight-forward.

The trick is to pass EOF to /bin/bash, and the LAST line of the script (containing EOF) MUST NOT contain any other char. Even indention may cause problems, so simply remove all chars - that is why it is not "nicely" aligned.

Then it works. Thanks a lot, everyone!

Atais
  • 10,857
  • 6
  • 71
  • 111
0

For example you have a list of ip addresses in txt file and you want to check amount of java processes on each box writing ip address right after amount of processes . You can do the following :

cat ipv4.txt | xargs -I IP sh -c 'ssh username@IP "ps aux | grep java | grep -v grep | wc -l " && echo IP'

Inline your command and have fun.

Roman Bondar
  • 82
  • 1
  • 6