How to use single quotes inside awk statement that is surrounded by single quotes? - linux

I'm having issues implementing this awk statement that I need for my script:
rsh fooDNS '
...
BROADCAST_IP_ADDRESS=$(/usr/sbin/ifconfig $IF_NAME | grep broadcast | awk '{print \$6}')
...
'
The issue here is that the statement above is contained within an rsh command surrounded by single quotations. Consequently, bash cannot interpret the single quotations around {print $6}, which is giving me a lot of problems. So far, I haven't been able to determine how to get around this issue.

You can't nest single quotes, but you can end the single quoted string, include an escaped single quote, and then re-enter the quotes. Try this:
rsh fooDNS '
...
BROADCAST_IP_ADDRESS=$(/usr/sbin/ifconfig $IF_NAME | grep broadcast | awk '\''{print $6}'\'')
...
'
Nonetheless, this kind of quoting madness gets ugly very quickly. If at all possible, I recommend using scp/rcp/ftp to copy a normal bash script over to the remote and then run that. Failing that, I think you can use a trick like this if you don't need to feed anything to the script's stdin:
cat script_file | rsh fooDNS bash
(Use rsh fooDNS /bin/sh if your script is plain-sh-compatible and the remote side doesn't have bash, of course.)
As yet another alternative, if your snippet is short you can use here docs:
rsh fooDNS sh <<'EOF'
...
BROADCAST_IP_ADDRESS=$(/usr/sbin/ifconfig $IF_NAME | grep broadcast | awk '{print $6}')
...
EOF

Replace the embedded single quotes by the sequence '\'' each time. In theory, you can just do:
rsh fooDNS '
...
BROADCAST_IP_ADDRESS=$(/usr/sbin/ifconfig $IF_NAME | grep broadcast |
awk '\''{print $6}'\'')
...
'
The first ' ends the current single quoted string; the \' sequence adds a single quote; the final ' restarts a new (but contiguous) single-quoted string. So, this introduces no spaces or anything.
On the other hand, it is best to avoid needing to do that. It is vulnerable to causing problems when the string is reinterpreted. And this is doubly the case when dealing with remote shells.

I usually use double quotes for deep nesting when doing it manually, or a mix of double and single quotes automatically.
If you do it manually, it's probably simpler to just escape your nested double quotes, apostrophes and dollar signs with backslashes, and avoid doing more than one or two levels deep.
Sometimes, instead of nesting the quotes manually, I'll use:
http://stromberg.dnsalias.org/~strombrg/bashquote.html
It can wrap up a string with double quotes automatically, exponentially. It uses a mix of double quotes and single quotes.
EG. from a minimal test of the code:
dstromberg#zareason-limbo6000a ~/src/home-svn/bashquote/trunk $ ./bashquote.py
unquoted: 'This is a test'
repetition 0: ''"'"'This is a test'"'"''
repetition 1: ''"'"''"'"'"'"'"'"'"'"'This is a test'"'"'"'"'"'"'"'"''"'"''
repetition 2: ''"'"''"'"'"'"'"'"'"'"''"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'This is a test'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"''"'"'"'"'"'"'"'"''"'"''
Final version: ''"'"''"'"'"'"'"'"'"'"''"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'This is a test'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"''"'"'"'"'"'"'"'"''"'"''
''"'"''"'"'"'"'"'"'"'"''"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'This is a test'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"'"''"'"'"'"'"'"'"'"''"'"''
That should be good for hopping through 3 ssh's and executing on the 4th.

For AWK scripts I set a variable to the octal equivalent.
But in a case like yours, I would use double quotes and make sure to escape everything that might be interpreted by the shell such as the dollar sign as you have done.
And I wouldn't use rsh since it's insecure.

Related

how to escape file path in bash script variable

I would like to escape a file path that is stored in a variable in a bash script.
I read several threads about escaping back ticks or but it seems not working as it should:
I have this variable:
The variables value is entered during the bash script execution as user parameter
CONFIG="/home/teams/blabla/blabla.yaml"
I would need to change this to: \/home\/teams\/blabla\/blabla.yaml
How can I do that with in the script via sed or so (not manually)?
With GNU bash and its Parameter Expansion:
echo "${CONFIG//\//\\/}"
Output:
\/home\/teams\/blabla\/blabla.yaml
Using the solution from this question, in your case it will look like this:
CONFIG=$(echo "/home/teams/blabla/blabla.yaml" | sed -e 's/[]\/$*.^[]/\\&/g')
echo "/home/teams/blabla/blabla.yaml" | sed 's/\//\\\//g'
\/home\/teams\/blabla\/blabla.yaml
explanation:
backslash is used to set the following letter/symbol as an regular expression or vice versa. double backslash is used when you need a backslash as letter.
Why does that need escaping? Is this an XY Problem?
If the issue is that you are trying to use that variable in a substitution regex, then the examples given should work, but you might benefit by removing some of the "leaning toothpick syndrom", which many tools can do just by using a different match delimiter. sed, for example:
$: sed "s,SOME_PLACEHOLDER_VALUE,$CONFIG," <<< SOME_PLACEHOLDER_VALUE
/home/teams/blabla/blabla.yaml
Be very careful about this, though. Commas are perfectly valid characters in a filename, as are almost anything but NULLs. Know your data.

Double /Single quote syntax

When querying a list and putting the value in a variable and trying to use the variable in another script it doenst get the format needed.
script 1:
cilist=$(opr-ci-list.sh -view_name TN_UD_REFRESH_MRE | sed -e '/^[TL-]/d' -e '/^\s*$/d' -e 's/^....//' | awk -vORS=, '{ print $1 }' | sed 's/,$/\n/')
The output of this script will be ID's comma seperated string like: 7c553435c1376c8f5f020fcee0b8ef51,7d427dd75235bf513286d3210e1bd787
echo $cilist
7c553435c1376c8f5f020fcee0b8ef51,7d427dd75235bf513286d3210e1bd787
=> no quotes to be seen when doing a echo
script 2:
opr-downtime.sh -cis "\"$cilist\""
i receive an error because the are single quotes surrounding the variable:
-cis '"7c553435c1376c8f5f020fcee0b8ef51,7d427dd75235bf513286d3210e1bd787 "'
I tried several syntax ways but keep getting the wrong input for the second script. Or i have no quotes or quotes like '" in front and behind.
Any help or feedback on the correct syntax would be appreciated.
The shell treats the quote characters as special characters. For double quote ("), it treats the enclosed data as a single argument to the command. This would be useful if the input had a space (or other shell separator token) within it. However, when the argument is provided to the command, the quote is removed.
You can try using backslash (\) to escape the double quote. But, you may still want to enclose everything with a double quote incase $cilist has input that requires quoting.
script.sh -cis "\"$cilist\""

Bash prompt scripting

I'm trying to follow a guide found here, but I do not like what I see as a cop out. In the script they set PS1 to
PS1="<code> `cat /proc/loadavg | awk '{print $1}'` <more code>"
My problem with this is I would like to know if it is possible to write it with single quotes like:
PS1='<code> `cat /proc/loadavg | awk \'{print $1}\'` <more code>'
So it is evaluated every time I run the command, not just the once. It seems the presence of the single quotes in awk are forcing me to use double quotes. I would like to have this run after every prompt and I have another awk tidbit of code I would like to run here as well.
If this would be too cumbersome for bash to do, then I'm fine not having it, it's more for proof of concept anyways.
You can't put a single quote into single quotes, you have to end the single quotes, insert the quote, and start single quotes again:
PS1='$(code | awk '\''{print $1}'\'')'
# or
PS1='$(code | awk '"'"'{print $1}'"'"')'

how to remove first two words of a strings output

I want to remove the first two words that come up in my output string. this string is also within another string.
What I have:
for servers in `ls /data/field`
do
string=`cat /data/field/$servers/time`
This sends this text:
00:00 down server
I would like to remove "00:00 down" so that it only displays "server".
I have tried using cut -d ' ' -f2- $string which ends up just removing directories that the command searches.
Any ideas?
Please, do the things properly :
for servers in /data/field/*; do
string=$(cut -d" " -f3- /data/field/$servers/time)
echo "$string"
done
backticks are deprecated in 2014 in favor of the form $( )
don't parse ls output, use glob instead like I do with data/field/*
Check http://mywiki.wooledge.org/BashFAQ for various subjects
Use -d option to set the delimtier to space
$ echo 00:00 down server | cut -d" " -f3-
server
Note Use the field number 3 as the count starts from 1 and not 0
From man page
-d, --delimiter=DELIM
use DELIM instead of TAB for field delimiter
N- from N'th byte, character or field, to end of line
More Tests
$ echo 00:00 down server hello world| cut -d" " -f3-
server hello world
The for loop is capable of iterating through the files using globbing. So I would write something like
for servers in /data/field*
do
string=`cut -d" " -f3- /data/field/$servers/time`
...
...
You can use sed as well:
sed 's/^.* * //'
For the examples given, I prefer cut. But for the general problem expressed by the question, the answers above have minor short-comings. For instance, when you don't know how many spaces are between the words (cut), or whether they start with a space or not (cut,sed), or cannot be easily used in a pipeline (shell for-loop). Here's a perl example that is fast, efficient, and not too hard to remember:
| perl -pe 's/^\s*(\S+\s+){2}//'
Perl's -p operates like sed's. That is, it gobbles input one line at a time, like -n, and after dong work, prints the line again. The -e starts the command-line-based script. The script is simply a one-line substitute s/// expression; substitute matching regular expressions on the left hand side with the string on the right-hand side. In this case, the right-hand side is empty, so we're just cutting out the expression found on the left-hand side.
The regular expression, particular to Perl (and all PLRE derivatives, like those in Python and Ruby and Javascript), uses \s to match whitespace, and \S to match non-whitespace. So the combination of \S+\s+ matches a word followed by its whitespace. We group that sub-expression together with (...) and then tell sed to match exactly 2 of those in a row with the {m,n} expression, where n is optional and m is 2. The leading \s* means trim leading whitespace.

Extracting a string in csh

Would you please explain why the following shell command wouldn't work:
sh-3.1$ echo $MYPATH
/opt/Application/DATA/CROM/my_application
sh-3.1$ awk '{print substr($MYPATH,3)}'
Thanks
Best Regards
MYPATH is not going to be substituted by the shell since the string uses single quotes. Consider the following:
csh$ echo '{print substr($USER,3)}'
{print substr($USER,3)}
csh$ echo "{print substr($USER,3)}"
{print substr(dshawley,3)}
The usage of single quotes instructs the shell to pass the string argument to the program as-is. Double quotes tell the shell to perform variable expansion on the argument before passing it to the program. This is a basic shell feature that is common amongst shells and some programming languages (e.g., perl).
The next problem that you are going to run into is that awk will want quotes around the first parameter to substr or the parse will fail. You will probably see an "Illegal variable name" warning in this case. This is where I get lost with csh since I have no clue how to properly escape a double-quote within a quoted string. In bash/sh/ksh, you would do the following:
sh$ awk "{print substr(\"$USER\",3)}"
input
^D
hawley
sh$
Just in case you do not already know this, awk will require an input stream before it is going to do anything. I had to type "input" and the EOF character for the little example.
Quoting and escaping
"string" is a weak quote. Enclosed whitespace and wildcards are taken as literals, but variable and command substitutions are still performed.
'string' is a strong quote. The entire enclosed string is taken as a literal.
You can use the -v option to pass variable to awk:
awk -v mypath=$MYPATH 'BEGIN{print substr(mypath, 3)}'

Resources