How to kill multiple processes on a remote server with bash - bash

I have this very simple bash code that should kill a list of tail -f processes on a remote server.
old_tailf_pids=`ssh root#$server "ps -ef | grep 'tail -f -n +1 /opt/wd' | grep root | grep -v grep | sed -e \"s#root *\([0-9]\+\) .*#\1#g\""`
echo $old_tailf_pids
echo "Killing old tailfs..."
ssh root#$server "kill -9 $old_tailf_pids"
Output:
4007 5281 5906 8265 8823 9918 10477 11587 12213 12753 13396 13976 14558 15985 16788 18128 18762 19412 20109 21393 28924 29487 31542 32155
Killing old tailfs...
bash: line 1: 5281: command not found
bash: line 2: 5906: command not found
bash: line 3: 8265: command not found
bash: line 4: 8823: command not found
bash: line 5: 9918: command not found
...
Seems like the SSH command killed only the first pid, and then tried to 'run' the rest of the pids. Any idea why?
Thanks

As it is evident from comments below the question that variable contains newlines after each process id, you may use this xargs command in remote ssh:
ssh root#$server "xargs kill -9 <<< \"old_tailf_pids\""

Related

Execute command via ssh [duplicate]

This question already has an answer here:
Bash command substitution on remote host [duplicate]
(1 answer)
Closed 3 years ago.
I want to kill process. Without kill cmd it works fine. But with kill cmd i get:
grep: invalid option -- 'S'
Usage: grep [OPTION]... PATTERN [FILE]...
Try 'grep --help' for more information.
awk: cmd. line:1: {print
awk: cmd. line:1: ^ unexpected newline or end of string
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
Doesn't work:
ssh someUser#someHost kill $(ps -aux | grep 'screen -S cats' | awk '{print $2}')
Works fine:
ssh someUser#someHost ps -aux | grep 'screen -S cats' | awk '{print $2}'
The command substitution runs ps locally, to produce the argument for the remote kill command.
To make the command substitution run remotely, quote the entire string (which is a good idea; you generally don't want ssh having to figure out how to join its arguments into a single command).
# Using $'...', which may contain escaped single quotes
ssh someUser#someHost $'kill $(ps -aux | awk \'/screen -S cats/ {print $2}\''
or
# Using standard double quotes, but making the user responsible
# for escaping any dollar signs that need to be passed literally.
ssh someUser#someHost "kill \$(ps -aux | awk '/screen -S cats/ {print \$2}'"

Watch with Process Substitution

I often run the command
squeue -u $USER | tee >(wc -l)
where squeue is a Slurm command to see how many jobs you are running. This gives me both the output from squeue and automatically tells how many lines are in it.
How can I watch this command?
watch -n.1 "squeue -u $USER | tee >(wc -l)" results in
Every 0.1s: squeue -u randoms | tee >(wc -l) Wed May 9 14:46:36 2018
sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `squeue -u randoms | tee >(wc -l)'
From the watch man page:
Note that command is given to "sh -c" which means that you may need to use extra quoting to get the desired effect.
sh -c also does not support process substitution, the syntax you're using here as >().
Fortunately, that syntax isn't actually needed for what you're doing:
watch -n.1 'out=$(squeue -u "$USER"); echo "$out"; { echo "$out" | wc -l; }'
...or, if you really want to use your original code even at a heavy performance penalty (starting not just one but two new shells every tenth of a second -- first sh, and then bash):
bash_cmd() { squeue -u "$USER" | tee >(wc -l); } # create a function
export -f bash_cmd # export function to the environment
watch -n.1 'bash -c bash_cmd' # call function from bash started from sh started by watch

Script to restart another script

Hello I am trying to write a script to restart other script from command line.
usage should be:
restart someotherscript.sh
cat restart
#!/bin/bash
for pids in $(ps -ef | grep $1 | grep -v grep | awk '{print $2}')
do
kill -9 $pids
done
echo test
sleep 10
$1 &
output is:
root#xxxx:/scripts# restart pricealert.sh
Killed
root#xxxx:
My restart script is killing itself.
What is wrong here? Can you please help me?
Your script is finding itself in the search results because the command you used to start the script contains the script name you're trying to kill.
You can add an if statement to fix this ($$ is the pid of the running script):
if [ "$$" != "$pids" ]; then
kill -9 $pids
fi

How to access the PID from an lsof.

Given the following command lsof -i:1025 I get:
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
ruby 12345 john 11u IPv4 0xb2f4161230e18fd57 0t0 TCP localhost:foobar (LISTEN)
I am trying to write a script to get that PID (12345) and kill it. At the moment I have to run lsof -i:1025, get that PID and then run kill -9 12345.
The lsof(8) man page says:
-t specifies that lsof should produce terse output with process
identifiers only and no header - e.g., so that the output
may be piped to kill(1). -t selects the -w option.
You can use lsof -t -i:1025 | xargs kill -9.
Something like:
#!/bin/bash --
x=`lsof -Fp -i:1025`
kill -9 ${x##p}
Should do it. The 3rd line runs lsof using the -F option to get just the pid, with a leading p. The next line drops the leading p from the output of lsof and uses the result as the pid in a kill command.
Edit: At some point lsof was modified so the file descriptor preceded by an f is always output, whether you ask for it or not (which makes no sense to me, but what do I know). While you could put a | grep '^p' in the back quotes, an easier way is to use the -t option, as noted in fabianopinto's answer below.
man lsof says that you can use -F to specify fields to to be output for processing by other programs. So you can do something like
lsof -i:1025 -Fp | sed 's/^p//' | xargs kill -9
Further to #blm's answer, it didn't work for me exactly because the output of the lsof command was:
p4679
f33
So with the ${x##p} was
4679
f33
The solution
Grab only the first line with | head -n 1:
x=`lsof -Fp -i:"$1" | head -n 1`
kill -9 ${x##p}
And furthermore from #blm's and #Mosh Feu's answers:
lsof -i:1337 -Fp | head -n 1 | sed 's/^p//' | xargs kill
is what ended up doing the trick for me.
I recommend adding this as a bash function and aliasing it
alias kbp='killByPort'
killByPort() {
lsof -i:$1 -Fp | head -n 1 | sed 's/^p//' | xargs kill
}
This shortcut will kill the process quickly for you
kill -9 $(lsof -t -i :3000)
for fish shell users, simply remove the $ sign, so
kill -9 (lsof -t -i :3000)

SSH in a script - commands not running on remote server [duplicate]

This question already has answers here:
Execute a command on remote hosts via ssh from inside a bash script
(4 answers)
Closed 7 years ago.
I need a help with a bash script that connect to server as root, execute some commands and then exit from the server.
I tried this script but when login login to server performed the command not running !
#!/bin/bash
sudo ssh -o ConnectTimeout=10 $1 'exit'
if [ $? != 0 ]; then
echo "Could not connect to $1 , script stopped"
exit
fi
sudo ssh $1
echo "SRV=`cat /etc/puppet/puppet.conf | grep -i srv_domain | awk '{print $3}'`"
echo $SRV
echo "puppetMaster=`host -t srv _x-puppet._tcp.$SRV | head -1 | awk '{print $8}' | cut -f1 -d"."`"
echo $puppetMaster
'exit'
I'm surprised nobody has suggested a heredoc yet.
sudo ssh "$1" <<'EOF'
SRV=`cat /etc/puppet/puppet.conf | grep -i srv_domain | awk '{print $3}'`
echo $SRV
echo "puppetMaster=`host -t srv _x-puppet._tcp.$SRV | head -1 | awk '{print $8}' | cut -f1 -d"."`"
echo $puppetMaster
EOF
This feeds everything from the <<'EOF' until the line starting with EOF into the stdin of ssh, to be received and run by the remote shell.
The commands following ssh machine in a script are not run on the machine. They will be run on the local machine once the ssh exits.
Either specify the commands to run as an argument of ssh, or alternatively, run ssh and make it read the commands from standard input, and send the commands to it.
ssh machine ls
# or
echo ls | ssh machine
You seem to be a little confused as to what runs where.
ssh -o ConnectTimeout=10 $1 'exit'
will connect to $1, run exit, and disconnect.
ssh -o ConnectTimeout=10 $1 'echo hello world'
will print hello world on
the server and then disconnect.
ssh $1
will open up a shell on the remote. After the shell has ended, the following commands will run locally.
echo "SRV=`cat /etc/puppet/puppet.conf | grep -i srv_domain | awk '{print $3}'`"
echo $SRV
echo "puppetMaster=`host -t srv _x-puppet._tcp.$SRV | head -1 | awk '{print $8}' | cut -f1 -d"."`"
echo $puppetMaster
'exit'
What you probably want is start bash on the remote and forward to it the commands you want to give it via stdin.
echo "my commands" | ssh $1 bash
Technically, you don't need that bash -- ssh will start bash even without it (but with different rc files).

Resources