You were pretty close with your example. It works just fine when you use it with arguments such as these.
Sample script:
$ more ex.bash
#!/bin/bash
echo $1 $2
Example that works:
$ ssh serverA "bash -s" < ./ex.bash "hi" "bye"
hi bye
But it fails for these types of arguments:
$ ssh serverA "bash -s" < ./ex.bash "--time" "bye"
bash: --: invalid option
...
What's going on?
The problem you're encountering is that the argument, -time
, or --time
in my example, is being interpreted as a switch to bash -s
. You can pacify bash
by terminating it from taking any of the remaining command line arguments for itself using the --
argument.
Like this:
$ ssh root@remoteServer "bash -s" -- < /var/www/html/ops1/sysMole -time Aug 18 18
Examples
#1:
$ ssh serverA "bash -s" -- < ./ex.bash "-time" "bye"
-time bye
#2:
$ ssh serverA "bash -s" -- < ./ex.bash "--time" "bye"
--time bye
#3:
$ ssh serverA "bash -s" -- < ./ex.bash --time "bye"
--time bye
#4:
$ ssh < ./ex.bash serverA "bash -s -- --time bye"
--time bye
NOTE: Just to make it clear that wherever the redirection appears on the command line makes no difference, because ssh
calls a remote shell with the concatenation of its arguments anyway, quoting doesn't make much difference, except when you need quoting on the remote shell like in example #4:
$ ssh < ./ex.bash serverA "bash -s -- '<--time bye>' '<end>'"
<--time bye> <end>
Something in your .bashrc
is assuming that the shell is running on a terminal. That's perfectly fine: .bashrc
is supposed to run only in interactive shells, and interactive shells are supposed to run only on terminals.
The problem is that you're systematically including .bashrc
from .profile
. That's wrong: you should only include .bashrc
in interactive shells.
Change your .profile
to
# Bash doesn't load its interactive initialization file if it's invoked as
# a login shell, so do it manually.
case $- in
*i*) if [ -n "$BASH" ]; then . ~/.bashrc;; fi
esac
Move mesg n
into .bashrc
: it's a terminal-related command, not a session-related command.
If you have environment variable definitions in your .bashrc
, move them to .profile
. The .profile
file is for things that are executed when your session starts, typically mainly environment variable definitions, used by any application that you'll run during the session. The .bashrc
file is the configuration file for bash when running interactively, it typically contains terminal setup, alias definitions, shell options and completion settings, and other things related to the interactive use of the shell.
For background, see:
Best Answer
With respect to checking if the process is already running I'd change what you're doing slightly and use
pgrep
instead.Example
The
-f
switch allowspgrep
to match the entire command line and not just the first part.Command line arguments
For this you have a couple of methods. You could try parsing them from the output of
pgrep
as well. You'll need to add an additional switch,-a
.Example
Then use
awk
,sed
or something similar to parse their output.sed
awk
These 2 methods are off the top of my head, they could no doubt be streamlined.
Using /proc/
But depending on the number of arguments and the length this could cause you issues if the command line is overly long in length. So I'd probably go with the second method and parse the contents of the process's
cmdline
file. Every process has a set of files within Linux'/proc
filesystem that contains meta information about that process.One of these files is the file
cmdline
. But you have to pay special attention to the contents of this file. The arguments within this file are separated by NUL characters. You can usecat -v <file>
to see them in a terminal window.This substitutes
^@
in place of the NUL's.So parsing the contents can be done in a variety of ways, one method is discussed in @Joesph's answer, using
xargs -0 ...
. Another is usingcat -v
.Examples
xargs
cat
You can use
sed
to cleanup this 2nd method a bit.References