Escape single quotes ssh remote command - bash

I read any solutions for escape single quotes on remote command over ssh. But any work fien.
I'm trying
ssh root#server "ps uax|grep bac | grep -v grep | awk '{ print $2 }' > /tmp/back.tmp"
Don't work awk
ssh root#server "ps uax|grep bac | grep -v grep | awk \'{ print $2 }\' > /tmp/back.tmp"
....
awk: '{
awk: ^ caracter ''' inválido en la expresión
And try put single quotas on command but also don't work.
Aprecite help

The ssh command treats all text typed after the hostname as the remote command to executed. Critically what this means to your question is that you do not need to quote the entire command as you have done. Rather, you can just send through the command as you would type it as if you were on the remote system itself.
This simplifies dealing with quoting issues, since it reduces the number of quotes that you need to use. Since you won't be using quotes, all special bash characters need to be escaped with backslashes.
In your situation, you need to type,
ssh root#server ps uax \| grep ba[c] \| \'{ print \$2 }\' \> /tmp/back.tmp
or you could double quote the single quotes instead of escaping them (in both cases, you need to escape the dollar sign)
ssh root#server ps uax \| grep ba[c] \| "'{ print \$2 }'" \> /tmp/back.tmp
Honestly this feels a little more complicated, but I have found this knowledge pretty valuable when dealing with sending commands to remote systems that involve more complex use of quotes.

In your first try you use double-quotes " so you need to escape the $ character:
ssh root#server "ps uax|grep bac | grep -v grep | awk '{ print \$2 }' > /tmp/back.tmp"
▲
Also, you can use:
ps uax | grep 'ba[c]' | ...
so then you don't need the grep -v grep step.

Related

How to remove the username/hostname line from an output on Korn Shell?

I run the command
df -gP /data1 /data2 | grep -v File | awk '{print $1}' |
awk -F/dev/ '$0=$2' | tr '\n' '
on the AIX shell (ksh) and it prints the output below:
lv_data01 lv_data02 root#testhost:/
However, I would like the output to be printed this way. Could someone help?
lv_data01 lv_data02
Using grep … | awk … | awk … is not necessary; a single awk could do the whole job. So could sed and it might even be easier. I'd be tempted to deal with the spacing by using:
x=$(df … | sed …); echo $x
The tr command, once corrected, replaces newlines with spaces, so the prompt follows without a newline before it. The ; echo suggestion adds the missing newline; the echo $x suggestion (note no double quotes) does too.
As for the sed command:
sed -n '/File/!{ s/[[:space:]].*//; s%^.*/dev/%%p; }'
Don't print anything by default
If the line doesn't match File (doing the work of grep -v):
remove the first space (blank or tab) and everything after it (doing the work of awk '{print $1}')
replace everything up to /dev/ with nothing and print (doing the work of awk -F/dev/ '{$0=$2}')
The command substitution and capture, followed by echo, deals with spaces and newlines.
So, my suggested solution is:
x=$(df -gP /data1 /data2 | sed -n '/File/!{ s/[[:space:]].*//; s%^.*/dev/%%p; }'); echo $x
You could add unset x after the echo if you are going to be using this directly in the shell and not in a shell script. If it'll be encapsulated in a shell script, you don't have to worry about it.
I'm blithely assuming the output from df -gP won't contain a path such as this, with two occurrences of /dev:
/who/knows/dev/lv_data01/dev/bin
If that's a real problem, you can fix the sed script, but I don't think it will be. It's one thing the second awk script in the question handles differently.

How to parse variable to sed command in shell?

I have some variables:
$begin=10
$end=20
how to pass them to sed command.
sed -n '$begin,$endp' filename | grep word
sed -n '10,20p' filename | grep word
The reason this doesn't work is that single quotes in shell code prevent variable expansion. The good way is to use awk:
awk -v begin="$begin" -v end="$end" 'NR == begin, NR == end' filename
It is possible with sed if you use double quotes (in which shell variables are expanded):
sed -n "$begin,$end p" filename
However, this is subject to code injection vulnerabilities because sed cannot distinguish between code and data this way (unlike the awk code above). If a user manages to set, say, end="20 e rm -Rf /;", unpleasant things can happen.

bash invalid delimiter in cut command

tab="`\echo '\t'`"
grep "^.*${tab}.*${tab}.*${tab}.*${tab}.*${tab}" $file |
grep -vi ssm_id |
cut -f 1,5,6 -d "${tab}" > $rmloadfile
I am getting error as
-cut: invalid delimiter
the above code is part of my bash script.
Ignoring the actual problem, you really want to use awk here instead of this combination of grep and cut:
awk 'NF>=6 && tolower($0) !~ ssm_id { print $1, $5, $6 }' $file > $rmloadfile
The echo command doesn't interpret backslash escaped characters by default. It has to be enabled using the -e switch.
If you use:
tab="$(echo -e '\t')"
it works.
But I'd rather recommend using the approach proposed by #devnull in the comments, or refer to the linked question.

bash command quoted by single quote

I need to find process by string matching, and the kill it, need to do it in one line in another script file:
here's what I tried:
'kill $(ps -ef|grep xxx|grep -v grep | awk '{print $2 }' )'
"kill $(ps -ef|grep xxx|grep -v grep | awk '{print $2 }' )"
first one didn't work because of the nested single quote, second one didn't work because $2 is taken by the parent script to be argument 2 to parent script.
how do I do this?
The easiest way to accomplish that task is:
pkill xxx
(which you'll find in the debian/ubuntu world in package procps, if you don't have it installed.) You might need to use pkill -f xxx, depending on whether xxx is part of the process name or an argument, which is often the case with script execution.
However, to answer the more general question about shell-quoting, if you need to pass the string
kill $(ps aux | grep xxx | grep -v grep | awk '{print $2}')
as an argument, you need to use backslash escapes:
bash -c "kill \$(ps aux | grep xxx | grep -v grep | awk '{print \$2}')"
Or, you can paste together several quoted strings:
bash -c 'kill $(ps aux | grep xxx | grep -v grep | awk '"'"'{print $2}'"'"')'
Personally, I find the first one more readable but YMMV.
You can only backslash escape a few characters inside a double-quoted string: $, ", \, newline and backtick; and inside a single-quoted string backslash is just backslash. However, that's enough to let you type just about anything.

Alias if script matches variable, quotation issues

I'm trying to write an alias for a common command to cancel a process, but I'm having issues with the single and double quotations. This is my first attempt at Bash scripting and I'm a bit stumped.
lsof -i tcp:80 | awk '$1 == "Google" {print $2}'
This works as a stand-alone command and outputs the correct PID.
When I try formatting it as an alias though I'm having issues. I know the command is stopping at the first single quote by the way this is structure but I'm not sure how to fix it.
alias test='lsof -i tcp:80 | awk '$1=="Google" {print $2}''
There's no escape sequence for single quotes inside single quotes. You can't write \' like you might expect. So there are two options.
You can break out of single quotes, add an escaped single quote \', and then go back in, like so:
alias test='lsof -i tcp:80 | awk '\''$1 == "Google" {print $2}'\'
You can use double quotes. You then have to escape not just the double quotes inside the string but also the dollar signs.
alias test="lsof -i tcp:80 | awk '\$1 == \"Google\" {print \$2}'"
Try defining your alias like this
alias test='lsof -i tcp:80 | awk '"'"'$1=="Google" {print $2}'"'"
The single quotes ' must be escaped between double quotes ". To do so, the command has to be split into several parts to escape them differently. lsof -i tcp:80 | awk '$1=="Google" {print $2}' can be split on single quotes like this
lsof -i tcp:80 | awk
'
$1=="Google" {print $2}
'
Then quote with appropriate quotes
'lsof -i tcp:80 | awk'
"'"
'$1=="Google" {print $2}'
"'"
And merge every part together and you have your alias:
'lsof -i tcp:80 | awk'"'"'$1=="Google" {print $2}'"'"
Note that the first part does not contain any interpreted variable so it can be quoted with double quotes and merged with the second part. Thus the alias becomes
alias test="lsof -i tcp:80 | awk'"'$1=="Google" {print $2}'"'"
In almost every case where find yourself trying to define an alias, define a function instead.
testing () {
lsof -i tcp:80 | awk '$1=="Google" {print $2}'
}

Resources