How to suppress comments in linux ssh here script - linux

When using here script in a linux bash to run commands on a remote server all the lines are printed. How can the comments be suppressed?
The output of the below code should be:
ls
... (whatever is in this folder)
echo -e this is a test\ndone
this is a testndone
exit
Is this possible?
The reason for doing this is that the commands and comments are more complex making the output hard to read. That should be prettier.
#!/bin/bash
ssh -tt hogan#123.123.123.123 <<EOF
# this line get printed
ls
# and this comment also
echo -e this is a test\ndone
# exit ssh
exit
EOF
#end of script

I usually use sed to filter out comments and blank lines. The following will also strip comments that follow a command on the same line:
#!/bin/bash
sed 's/[[:blank:]]*#.*//; /^$/d' <<EOF | ssh -tt hogan#123.123.123.123
# this line get printed
ls
# and this comment also
echo -e "this is a test\ndone"
# exit ssh
exit
EOF

After the command try typing
| grep -v "^[[:space:]]*#"
so for example,
cat temp.txt | grep -v "^[[:space:]]*#"

I think you might be asking for this
grep -v '^[[:space:]]*#' <<EOF | ssh -tt hogan#123.123.123.123
# this line get printed
ls
# and this comment also
echo -e this is a test\ndone
# exit ssh
exit
EOF

Related

Run a command on remote machine and store its output in variable on remote machine

I want to capture number of rules of iptables that start with specific pattern in comment and then delete them. This is what I want to achieve. Here is my bash script
ssh -o "StrictHostKeyChecking no" root#$ip_address << EOF
echo "Now Removing your IPTables";
#storing output in input variable
input=$(iptables -nL INPUT --line-number | grep ip.* | cut -d " " -f1 | xargs)
#converting variable into an array
arr1=($input);
#loop through each element of array
echo "length:${#arr1[#]}";
for (( i="${#arr1[#]}"-1;i >=0; i-- ));
do
echo "$i:${arr1[$i]}"
iptables -D INPUT $i;
done;
EOF
Problem is the iptables command is not being executed on the remote machine and the output shows the length of arr1 is 0. But I am sure iptables has rules with my desired pattern.
Error being shown in terminal:
-bash: line 9: 3: command not found
Adding 2>&1 in the end of command also not working:
input=$(iptables -nL INPUT --line-number | grep ip.* | cut -d " " -f1 | xargs 2>&1)
TL;DR: Use <<"EOF" instead of <<EOF.
Your Here-Document will expand all variables and evaluate all subshells before the script is even sent to your ssh server.
Consider the following script:
ssh user#servername <<EOF
echo "$(hostname)"
EOF
This will not print servername (the name of the computer you are connecting to) but the name of your localhost instead (the name of the computer you working on).
Before ssh is executed, the subshell $(hostname) is executed. The resulting string "echo localhostname" is then passed to ssh and executed on the remote server.
To fix the problem you have to escape the $ inside the Here-Document or use a literal Here-Document:
ssh user#servername <<"EOF"
echo "$(hostname)"
EOF

How to log non-interactive bash command sent through ssh

I'm sending a command through ssh:
ssh server.org 'bash -s' << EOF
ls -al
whoami
uptime
EOF
How to log it in the system (remote server)? I'd like to log those commands in some file (.bash_history or /tmp/log).
I've tried to add the line below to sshd_config:
ForceCommand if [[ -z $SSH_ORIGINAL_COMMAND ]]; then bash; else echo "$SSH_ORIGINAL_COMMAND" >> .bash_history; bash -c "$SSH_ORIGINAL_COMMAND"; fi
But it logs "bash -s" only.
I'll appreciate any help.
When bash shell exits, bash reads and executes commands from the ~/.bash_logout file. Probably you can run the history command at the end in the .bash_logout(of the server) and save it to some location.
If it suffices to work with the given command, we can put the necessary additions to enable and log command history at the beginning and end, e. g.
ssh server.org bash <<EOF
set -o history
ls -al
whoami
uptime
history|sed 's/ *[0-9]* *//' >>~/.bash_history
EOF
Or we could put them into the awfully long ForceCommand line:
… if [[ "$SSH_ORIGINAL_COMMAND" == bash* ]]; then echo "set -o history"; cat; echo "history|sed 's/ *[0-9]* *//' >>~/.bash_history"; else cat; fi | bash -c "$SSH_ORIGINAL_COMMAND"; fi

"stdin: is not a tty" from cronjob

I'm getting the following mail every time I execute a specific cronjob. The called script runs fine when I'm calling it directly and even from cron. So the message I get is not an actual error, since the script does exactly what it is supposed to do.
Here is the cron.d entry:
* * * * * root /bin/bash -l -c "/opt/get.sh > /tmp/file"
and the get.sh script itself:
#!/bin/sh
#group and url
groups="foo"
url="https://somehost.test/get.php?groups=${groups}"
# encryption
pass='bar'
method='aes-256-xts'
pass=$(echo -n $pass | xxd -ps | sed 's/[[:xdigit:]]\{2\}/&/g')
encrypted=$(wget -qO- ${url})
decoded=$(echo -n $encrypted | awk -F '#' '{print $1}')
iv=$(echo $encrypted | awk -F '#' '{print $2}' |base64 --decode | xxd -ps | sed 's/[[:xdigit:]]\{2\}/&/g')
# base64 decode input and save to file
output=$(echo -n $decoded | base64 --decode | openssl enc -${method} -d -nosalt -nopad -K ${pass} -iv ${iv})
if [ ! -z "${output}" ]; then
echo "${output}"
else
echo "Error while getting information"
fi
When I'm not using the bash -l syntax the script hangs during the wget process. So my guess would be that it has something to do with wget and putting the output to stdout. But I have no idea how to fix it.
You actually have two questions here.
Why it prints stdin: is not a tty?
This warning message is printed by bash -l. The -l (--login) options asks bash to start the login shell, e.g. the one which is usually started when you enter your password. In this case bash expects its stdin to be a real terminal (e.g. the isatty(0) call should return 1), and it's not true if it is run by cron—hence this warning.
Another easy way to reproduce this warning, and the very common one, is to run this command via ssh:
$ ssh user#example.com 'bash -l -c "echo test"'
Password:
stdin: is not a tty
test
It happens because ssh does not allocate a terminal when called with a command as a parameter (one should use -t option for ssh to force the terminal allocation in this case).
Why it did not work without -l?
As correctly stated by #Cyrus in the comments, the list of files which bash loads on start depends on the type of the session. E.g. for login shells it will load /etc/profile, ~/.bash_profile, ~/.bash_login, and ~/.profile (see INVOCATION in manual bash(1)), while for non-login shells it will only load ~/.bashrc. It seems you defined your http_proxy variable only in one of the files loaded for login shells, but not in ~/.bashrc. You moved it to ~/.wgetrc and it's correct, but you could also define it in ~/.bashrc and it would have worked.
in your .profile, change
mesg n
to
if `tty -s`; then
mesg n
fi
I ended up putting the proxy configuration in the wgetrc. There is now no need to execute the script on a login shell anymore.
This is not a real answer to the actual problem, but it solved mine.
If you run into this problem check if you are getting all the environment variables set as you expect. Thanks to Cyrus for putting me to the right direction.

pseudo-terminal error will not be allocated because stdin is not a terminal - sudo

There are other threads with this same topic but my issue is unique. I am running a bash script that has a function that sshes to a remote server and runs a sudo command on the remote server. I'm using the ssh -t option to avoid the requiretty issue. The offending line of code works fine as long as it's NOT being called from within the while loop. The while loop basically reads from a csv file on the local server and calls the checkAuthType function:
while read inputline
do
ARRAY=(`echo $inputline | tr ',' ' '`)
HOSTNAME=${ARRAY[0]}
OS_TYPE=${ARRAY[1]}
checkAuthType $HOSTNAME $OS_TYPE
<more irrelevant code>
done < configfile.csv
This is the function that sits at the top of the script (outside of any while loops):
function checkAuthType()
{
if [ $2 == linux ]; then
LINE=`ssh -t $1 'sudo grep "PasswordAuthentication" /etc/ssh/sshd_config | grep -v "yes\|Yes\|#"'`
fi
if [ $2 == unix ]; then
LINE=`ssh -n $1 'grep "PasswordAuthentication" /usr/local/etc/sshd_config | grep -v "yes\|Yes\|#"'`
fi
<more irrelevant code>
}
So, the offending line is the line that has the sudo command within the function. I can change the command to something simple like "sudo ls -l" and I will still get the "stdin is not a terminal" error. I've also tried "ssh -t -t" but to no avail. But if I call the checkAuthType function from outside of the while loop, it works fine. What is it about the while loop that changes the terminal and how do I fix it? Thank you one thousand times in advance.
Another option to try to get around the problem would be to redirect the file to a different file descriptor and force read to read from it instead.
while read inputline <&3
do
ARRAY=(`echo $inputline | tr ',' ' '`)
HOSTNAME=${ARRAY[0]}
OS_TYPE=${ARRAY[1]}
checkAuthType $HOSTNAME $OS_TYPE
<more irrelevant code>
done 3< configfile.csv
I am guessing you are testing with linux. You should try add the -n flag to your (linux) ssh command to avoid having ssh read from stdin - as it normally reads from stdin the while loop is feeding it your csv.
UPDATE
You should (usually) use the -n flag when scripting with SSH, and the flag is typically needed for 'expected behavior' when using a while read-loop. It does not seem to be the main issue here, though.
There are probably other solutions to this, but you could try adding another -t flag to force pseudo-tty allocation when stdin is not a terminal:
ssh -n -t -t
BroSlow's approach with a different file descriptor seems to work! Since the read command reads from fd 3 and not stdin,
ssh and hence sudo still have or get a tty/pty as stdin.
# simple test case
while read line <&3; do
sudo -k
echo "$line"
ssh -t localhost 'sudo ls -ld /'
done 3<&- 3< <(echo 1; sleep 3; echo 2; sleep 3)

grep in bash script not working as expected

If I run
grep -i "echo" *
I get the results I want, but if I try the following simple bash script
#search.sh
grep -i "$1" *
echo "####--DONE--####"
and I run it with sh -x search.sh "echo" I get the following error output:
' grep -i echo '*
: No such file or directory
' echo '####--DONE--####
####--DONE--####
How come? I'm on CentOS
Add the sha-bang line at the top of your script
#!/bin/bash
and after making it executable, run the script using
./search.sh "echo"
The "sh -x" should print the files that '*' matches. It looks like it's not matching any files. Are you maybe running it in a directory with no readable files?

Resources