How to display newline in ssh - linux

I'm trying to do the following:
#!/bin/sh
ssh user#server "echo \"Test \n for newline\""
This displays:
test \n for newline
How do I get the shell to interpret \n as an actual newline?

Try using the -e option, e.g., echo -e "Test \n for newline".
If your echo doesn't have a -e option, then I'd use printf. It's widely available and it does not have nearly as many variations in it's implementations.

For greater portability, use printf instead of echo.
#!/bin/sh
ssh user#server 'printf "Test \n for newline"'
According to the POSIX standard, echo should process \n as a newline character. The bash built-in echo does not, unless you supply the -e option.

Just use one of
#!/bin/sh
ssh user#server "echo -e \"Test \n for newline\""
or
#!/bin/sh
ssh user#server 'echo -e "Test \n for newline"'
or
#!/bin/sh
ssh user#server "echo -e 'Test \n for newline'"
or even
#!/bin/sh
ssh user#server "echo 'Test
for newline'"
All of those will display
Test
for newline
(note the trailing space after the first line and the leading space before the second one - I just copied your code)

Before exectuning ssh command update the IFS environment variable with new line character.
IFS='
'
Store the ssh command output to a varaible
CMD_OUTPUT=$(ssh userName#127.0.0.1 'cat /proc/meminfo')
iterate the output per line
for s in $CMD_OUTPUT; do echo "$s"; done

Related

Using escape characters inside double quotes in ssh command in bash script

I want to run some commands each time when I log in to a remote system. Storing commands in .bashrc on remote is not an option.
What is the proper way to escape the escape chars inside of quotes in bash script for ssh?
How can I write each command in new line?
My script
#!/bin/bash
remote_PS1=$'\[\033[01;32m\]\u#\[\033[03;80m\]\h\[\033[00m\]:\[\033[01;34m\]\!:\w\[\033[00m\]\$ '
ssh -t "$#" 'export SYSTEMD_PAGER="";' \
'export $remote_PS1;' \
'echo -e "set nocompatible" > /home/root/.vimrc;' \
'bash -l;'
didn't work.
Escaping escape characters inside double-quotes and run them on remote server is way too complicated for me :)
Instead, I wrote a remoterc file for remote and a small remotessh script.
In remotessh, first I copy remoterc on remote machine and run bash command with that remoterc file interactively.
remoterc:
#!/bin/bash
SYSTEMD_PAGER=""
PS1="\[\033[01;32m\]\u#\[\033[03;80m\]\h\[\033[00m\]:\[\033[01;34m\]\!:\w\[\033[00m\]\$ "
echo -e "set nocompatible" > /home/root/.vimrc
remotessh:
#!/bin/bash
scp remoterc "$1":/home/root/
ssh "$1" -t "bash --rcfile remoterc -i"
It works :)
You can use Bash's printf %q.
According to help printf:
%q      quote the argument in a way that can be reused as shell input
See the following example:
$ cat foo.sh
ps1='\[\033[1;31m\]\u:\w \[\033[0m\]\$ '
ps1_quoted=$( printf %q "$ps1" )
ssh -t foo#localhost \
'export FOO=bar;' \
"export PS1=$ps1_quoted;" \
'bash --norc'
Result:

Passing a quoted string to ssh

So, i want to run this command in terminal
pssh -h hosts -i "echo "DenyUsers $1" >> /etc/ssh/sshd_config && service sshd config"
as you can see, " before echo words will be broken and it will be ended by " before DenyUsers $1 command.
I have changed " before echo and after config words and it doesn't still work like what i want.
I am newcomer in this scripting and i don't know what keywords should i put into the search engine :-)
Doing this in a manner that is safe even if you don't trust your input is a bit more involved.
Use printf %q to generate an eval-safe version of your data:
#!/usr/bin/env bash
# ^^^^- Requires an extension not available in /bin/sh
# printf %q is also available on ksh, but there you would write:
# echo_str=$(printf 'DenyUsers %q' "$1")
# cmd=$(printf '%q ' printf '%s\n' "$echo_str")
# as the ksh version doesn't have -v, but optimizes away the subshell instead.
printf -v echo_str 'DenyUsers %q' "$1"
printf -v cmd '%q ' printf '%s\n' "$echo_str"
pssh -h hosts -i "$cmd >> /etc/ssh/sshd_config && service sshd config"
Note that printf is used instead of echo for greater predictability; see the APPLICATION USAGE section of the POSIX specification for echo.
Did you try
pssh -h hosts -i "echo \"DenyUsers $1\" >> /etc/ssh/sshd_config && service sshd config"
or
pssh -h hosts -i 'echo "DenyUsers $1" >> /etc/ssh/sshd_config && service sshd config'
If the source of $1 can be trusted, then you can simply escape the inner double quotes with \:
pssh -h hosts -i "echo \"DenyUsers $1\" >> /etc/ssh/sshd_config && service sshd config"
The drawback to the approach above is what happens if the $1 expands to something malicious, for example, to $(rm -fr *). Then, /etc/ssh/sshd_config will end up containing:
echo "DenyUsers $(rm -fr *)"
which will run rm -fr * when executed.
For this reason, consider this answer for a safer solution based on printf %q.

Bash script runs one command before previous. I want them one after the other

So part of my script is as follows:
ssh user#$remoteServer "
cd ~/a/b/c/;
echo -e 'blah blah'
sleep 1 # Added this just to make sure it waits.
foo=`grep something xyz.log |sed 's/something//g' |sed 's/something-else//g'`
echo $foo > ~/xyz.list
exit "
In my output I see:
grep: xyz.log: No such file or directory
blah blah
Whereas when I ssh to the server, xyz.log does exist within ~/a/b/c/
Why is the grep statement getting executed before the echo statement?
Can someone please help?
The problem here is that your command in backticks is being run locally, not on the remote end of the SSH connection. Thus, it runs before you've even connected to the remote system at all! (This is true for all expansions that run in double-quotes, so the $foo in echo $foo as well).
Use a quoted heredoc to protect your code against local evaluation:
ssh user#$remoteServer bash -s <<'EOF'
cd ~/a/b/c/;
echo -e 'blah blah'
sleep 1 # Added this just to make sure it waits.
foo=`grep something xyz.log |sed 's/something//g' |sed 's/something-else//g'`
echo $foo > ~/xyz.list
exit
EOF
If you want to pass through a variable from the local side, the easy way is with positional parameters:
printf -v varsStr '%q ' "$varOne" "$varTwo"
ssh "user#$remoteServer" "bash -s $varsStr" <<'EOF'
varOne=$1; varTwo=$2 # set as remote variables
echo "Remote value of varOne is $varOne"
echo "Remote value of varTwo is $varTwo"
EOF
[command server] ------> [remote server]
The better way is to create shell script in the "remote server" , and run the command in the "command server" such as :
ssh ${remoteserver} "/bin/bash /foo/foo.sh"
It will solve many problem , the aim is to make things simple but not complex .

bash passing strings to "gnome-terminal -e"

this question looks like Opening multiple tabs in gnome terminal with complex commands from a cycle, but I am looking for a more generic solution.
I have a C program that calls a script "xvi" with arguments. Each argument is originally enclosed within quotes (''') and each quote in an argument is isolated and back-slashed (this format is a prerequisite) ex:
xvi 'a file' 'let'\''s try another'
The script xvi must launch gnome-terminal with "-e vim args"
With xterm instead of gnome-terminal, this is easy because xterm assumes that "-e" is the last argument and passes all the tail to the shell, so the following is OK:
exec /usr/bin/xterm -e /usr/bin/vim "$#"
For gnome-terminal, "-e" is an option among others and we need to 'package' the whole command line in one argument. This is what I have done, which is OK: Enclose each argument within double quotes(\"arg\") and backslash any double quote within an argument:
cmd="/usr/bin/vim"
while [ "$1" != "" ] ; do
arg=`echo "$1" | sed -e 's/\"/\\\"/g'`
cmd="$cmd \"$arg\""
shift
done
exec gnome-terminal --zoom=0.9 --disable-factory -e "$cmd"
Again, this works fine and I am nearly happy with that.
Question: Is there any nicer solution, avoiding the loop?
Thanks
Untested, but you could probably finagle printf '%q' into doing the job:
exec gnome-terminal --zoom=0.9 --disable-factory -e "$(printf '%q ' "$#")"
I know this thread is old but recently I had a similar need and I created a bash script to launch multiple tabs and run different commands on each of them:
#!/bin/bash
# Array of commands to run in different tabs
commands=(
'tail -f /var/log/apache2/access.log'
'tail -f /var/log/apache2/error.log'
'tail -f /usr/local/var/postgres/server.log'
)
# Build final command with all the tabs to launch
set finalCommand=""
for (( i = 0; i < ${#commands[#]}; i++ )); do
export finalCommand+="--tab -e 'bash -c \"${commands[$i]}\"' "
done
# Run the final command
eval "gnome-terminal "$finalCommand
You just need to add your commands in the array and execute.
Gist link: https://gist.github.com/rollbackpt/b4e17e2f4c23471973e122a50d591602

Linux bash script: share variable among terminal windows

If I do this:
#!/bin/bash
gnome-terminal --window-with-profile=KGDB -x bash -c 'VAR1=$(tty);
echo $VAR1; bash'
echo $VAR1
How can I get the last line from this script to work? I.e., be able to access the value of $VAR1 (stored on the new terminal window) from the original one? Currently, while the first echo is working, the last one only outputs an empty line.
The short version is that you can't share the variable. There's no shared channel for that.
You can write it to a file/pipe/etc. and then read from it though.
Something like the following should do what you want:
#!/bin/bash
if _file=$(mktemp -q); then
gnome-terminal --window-with-profile=KGDB -x bash -c 'VAR1=$(tty); echo "$VAR1"; declare -p VAR1 > '\'"$_file"\''; bash'
cat "$_file"
. "$_file"
echo "$VAR1"
fi

Resources