escaping special character while executing commands remotely using ssh - linux

When ran commands locally on the remote server outputs would work as expected:
desired_kernel_version="5.4.0-105-generic"
cat /tmp/grb.bkp | grep GRUB_DEFAULT
GRUB_DEFAULT=0
kernel_position=$(awk -F\' '$1=="menuentry " || $1=="submenu " {print i++ " : " $2}; /\tmenuentry / {print "\t" i-1">"j++ " : " $2};' /boot/grub/grub.cfg | grep "${desired_kernel_version}" | grep -v recovery | awk '{ print $1}' | sed 's/ //g')
echo $k_position
1>2
sed -i "s/GRUB_DEFAULT=0/GRUB_DEFAULT=\"${k_position}\"/g" /tmp/grb.bkp
cat /tmp/grb.bkp | grep GRUB_DEFAULT
GRUB_DEFAULT="1>2"
desired output when ran from remote server:
replace 0 of GRUB_DEFAULT value to kernel_position within quotes.
server=abcd
kernel_position=$(ssh -qT $server awk -F\' '$1=="menuentry " || $1=="submenu " {print i++ " : " $2}; /\tmenuentry / {print "\t" i-1">"j++ " : " $2};' /boot/grub/grub.cfg | grep "${desired_kernel_version}" | grep -v recovery | awk '{ print $1}' | sed 's/ //g')
ssh -qT $server "sed -i "s/GRUB_DEFAULT=0/GRUB_DEFAULT=\"${k_position}\"/g" /tmp/grb.bkp"

Suggesting to avoid quoting hell.
Send muli-line command into ssh by writing a script remote-script.sh with all lines.
remote-script.sh
#!/bin/bash
source ~/.bash_profile
$k_position=$1
desired_kernel_version="5.4.0-105-generic"
cat /tmp/grb.bkp | grep GRUB_DEFAULT
GRUB_DEFAULT=0
kernel_position=$(awk -F\' '$1=="menuentry " || $1=="submenu " {print i++ " : " $2}; /\tmenuentry / {print "\t" i-1">"j++ " : " $2};' /boot/grub/grub.cfg | grep "${desired_kernel_version}" | grep -v recovery | awk '{ print $1}' | sed 's/ //g')
echo $k_position
1>2
sed -i "s/GRUB_DEFAULT=0/GRUB_DEFAULT=\"${k_position}\"/g" /tmp/grb.bkp
cat /tmp/grb.bkp | grep GRUB_DEFAULT
GRUB_DEFAULT="1>2"
Give current user execution permissions on remote-script.sh
chmod u+x remote-script.sh
Use scp command to copy remote-script.sh to $server. If possible only once at deploy time.
scp -q remote-script.sh $server:/home/your-user
Use ssh command to run remote-script.sh on remote server. Pass $k_position in command line.
ssh -qT $server "bash -c /home/your-user/remote-script.sh $k_position"
BTW, in computing kernel_position, suggesting to fold all awk, grep, sed commands into a single awk script.

Related

How to direct linux bash script output to one line per host

I'd like to change my script(s) so that the command output is separated by a comma and is all on one line per host. Any ideas on how I can achieve this:
1st Script:
#!/bin/bash
for i in `cat ~/hostnames.txt`
do
ssh -q $i 'bash -s' < server_info.sh
done
2nd Script (server_info.sh):
#!/bin/bash
echo -n "Name: "
uname -n
echo -n "CPUs: "
cat /proc/cpuinfo* | grep processor | wc -l
echo -n "Memory (kb): "
cat /proc/meminfo | grep MemTotal: | awk '{print $2}'
echo -n "Current Kernel: "
uname -a | awk '{print $3}'
echo -n "IP: "
hostname -i
echo -e
Changing your 1st script:
#!/bin/bash
for i in cat ~/hostnames.txt
do
ssh -q $i 'bash -s' < server_info.sh
done | awk -v RS= '{$1=$1}1'
Note: Your server_info.sh can be a lot more optimized.For example:
cat /proc/meminfo | grep MemTotal: | awk '{print $2}'
could be changed to:
awk '/MemTotal:/{print $2}' /proc/meminfo

Trying to get the output of time command

When I run the below command on the terminal it's working fine.
$ var=`(time mysqldump -v -u'user' -p'password' database > db-backup.sql 2>
/tmp/mysqldump-output) 2>&1 | grep real | awk '{print $2}' | cut -f1 -d"m"`
$ echo $var
0
But when I use same command in the bash script it's not working properly
Below is script:
$ cat db-backup.sh
#!/bin/bash
var=`(time mysqldump -v -u'user' -p'password' database > database-backup.sql 2> /tmp/mysqldump-output) 2>&1 | grep real | awk '{print $2}' | cut -f1 -d"m"`
echo $var
script output:
$ sh -x db-backup.sh
+ grep real
+ awk {print $2}
+ cut -f1 -dm
+ var=
+ echo
After running the script with bash it worked.
$ bash -x db-backup.sh
++ grep real
++ awk '{print $2}'
++ cut -f1 -dm
+ var=0
+ echo 0
0

Not able to execute echo within legacy in Shell scripting

Below is my code and I am able to get the ssh connection. But after that it is doing nothing.
log_time="date +%F\%T"
PR_ONE="username#hostname"
file="/home/log.txt"
to_list="myemail"
echo "`$log_time`" >> $file
`ssh $PR_ONE "echo df -hP | grep fs1 | awk '{print $4}'"` >> $file
cat $file | mailx -s "Disk space usages" $to_list
I am getting the email but only with $log_time. I know that I am doing something wrong in quotations in the ssh line.
I am new to shell scripting.
Try this :
echo "df -hP | grep fs1 | awk '{print $4}'" | ssh -tt $PR_ONE >> $file
or prefer this :
ssh -tt $PR_ONE << EOF >> $file
df -hP | grep fs1 | awk '{print $4}'
EOF

Linux bash -c in command shell script

I am using ssh in a shell script in order to go on multiple linux server and get disk information on a particular disk. I am running following but I am not able to figure out the quote sequencing...In this example I am just capturing the header for my report....
ssh dbadmin#myserver bash -c '"df -kh | grep File | awk '{ print \$1 " | " \$2 " | " \$3 " | " \$4 " | " \$5 }' | tail -n -1"'
and following error...
bash: -c: line 0: syntax error near unexpected token |'
bash: -c: line 0:df -kh | grep File | awk { print | | | | } | tail -n -1'
Any help or suggestions would be great...
Thanks
Better to use quoted here-doc and avoid escaping:
ssh -t -t dbadmin#myserver<<'EOF'
df -kh | awk -v OFS=" | " '/file/{ print $1, $2, $3, $4, $5 }' | tail -n -1
EOF

What does this command does in shell linux

TMPFILE=/tmp/jboss_ps.$$
${PS} ${PS_OPTS} | \
grep ${JBOSS_HOME}/java | \
egrep -v " grep | \
tee | $0 " | ${AWK} '{print $NF " "}' | \
sort -u > ${TMPFILE} 2>/dev/null
I want to know what this precise line is doing from the code above
egrep -v " grep | \
tee | $0 "
At first i thought that that line is searching for everything that does not contain this exact string "grep | \ tee | $0" but it appears that egrep is processing the pipes, so what's the significance of the pipes here, does it mean OR ? From my test it appears that it's not, but if it means output redirection then what's the inner grep getting ? And why is tee alone too ?
AFAIK
egrep -v " grep | \
tee | $0 "
is nothing but
egrep -v " grep | tee | $0 "
where \ is the continuation character in bash.
egrep is same as grep -E
-v for inverted selection
tee just another string
so egrep -v " grep | tee | $0 " does find lines that have the string {java path} and within this results, all the lines that doesn't match the condition {either of grep OR tee OR $0 } where
$0 is the filename not a '$0' because it uses DOUBLE QUOTES and not single quotes :)
" commands | $variables " has the tendency to expand the variables and use the utility.
The commands in the pipeline before the egrep command is probably something like
ps -ef|grep .... The egrep -v (Option)line you asked about is simply omitting lines you
don't want in the results, in this case the initial grep command issued by the
script, any tee commands and lastly $0 which is the name of the this script
being executed. egrep allows to enter multiple patterns enclosed in double quotes and
separated by pipe symbol. Syntax egrep -[option or not] "patern1|patern2|patern..."

Resources