Output is not generating while running the bash script [duplicate] - sed

In Bash, what are the differences between single quotes ('') and double quotes ("")?

Single quotes won't interpolate anything, but double quotes will. For example: variables, backticks, certain \ escapes, etc.
Example:
$ echo "$(echo "upg")"
upg
$ echo '$(echo "upg")'
$(echo "upg")
The Bash manual has this to say:
3.1.2.2 Single Quotes
Enclosing characters in single quotes (') preserves the literal value of each character within the quotes. A single quote may not occur between single quotes, even when preceded by a backslash.
3.1.2.3 Double Quotes
Enclosing characters in double quotes (") preserves the literal value of all characters within the quotes, with the exception of $, `, \, and, when history expansion is enabled, !. The characters $ and ` retain their special meaning within double quotes (see Shell Expansions). The backslash retains its special meaning only when followed by one of the following characters: $, `, ", \, or newline. Within double quotes, backslashes that are followed by one of these characters are removed. Backslashes preceding characters without a special meaning are left unmodified. A double quote may be quoted within double quotes by preceding it with a backslash. If enabled, history expansion will be performed unless an ! appearing in double quotes is escaped using a backslash. The backslash preceding the ! is not removed.
The special parameters * and # have special meaning when in double quotes (see Shell Parameter Expansion).

The accepted answer is great. I am making a table that helps in quick comprehension of the topic. The explanation involves a simple variable a as well as an indexed array arr.
If we set
a=apple # a simple variable
arr=(apple) # an indexed array with a single element
and then echo the expression in the second column, we would get the result / behavior shown in the third column. The fourth column explains the behavior.
#
Expression
Result
Comments
1
"$a"
apple
variables are expanded inside ""
2
'$a'
$a
variables are not expanded inside ''
3
"'$a'"
'apple'
'' has no special meaning inside ""
4
'"$a"'
"$a"
"" is treated literally inside ''
5
'\''
invalid
can not escape a ' within ''; use "'" or $'\'' (ANSI-C quoting)
6
"red$arocks"
red
$arocks does not expand $a; use ${a}rocks to preserve $a
7
"redapple$"
redapple$
$ followed by no variable name evaluates to $
8
'\"'
\"
\ has no special meaning inside ''
9
"\'"
\'
\' is interpreted inside "" but has no significance for '
10
"\""
"
\" is interpreted inside ""
11
"*"
*
glob does not work inside "" or ''
12
"\t\n"
\t\n
\t and \n have no special meaning inside "" or ''; use ANSI-C quoting
13
"`echo hi`"
hi
`` and $() are evaluated inside "" (backquotes are retained in actual output)
14
'`echo hi`'
`echo hi`
`` and $() are not evaluated inside '' (backquotes are retained in actual output)
15
'${arr[0]}'
${arr[0]}
array access not possible inside ''
16
"${arr[0]}"
apple
array access works inside ""
17
$'$a\''
$a'
single quotes can be escaped inside ANSI-C quoting
18
"$'\t'"
$'\t'
ANSI-C quoting is not interpreted inside ""
19
'!cmd'
!cmd
history expansion character '!' is ignored inside ''
20
"!cmd"
cmd args
expands to the most recent command matching "cmd"
21
$'!cmd'
!cmd
history expansion character '!' is ignored inside ANSI-C quotes
See also:
ANSI-C quoting with $'' - GNU Bash Manual
Locale translation with $"" - GNU Bash Manual
A three-point formula for quotes

If you're referring to what happens when you echo something, the single quotes will literally echo what you have between them, while the double quotes will evaluate variables between them and output the value of the variable.
For example, this
#!/bin/sh
MYVAR=sometext
echo "double quotes gives you $MYVAR"
echo 'single quotes gives you $MYVAR'
will give this:
double quotes gives you sometext
single quotes gives you $MYVAR

Others explained it very well, and I just want to give something with simple examples.
Single quotes can be used around text to prevent the shell from interpreting any special characters. Dollar signs, spaces, ampersands, asterisks and other special characters are all ignored when enclosed within single quotes.
echo 'All sorts of things are ignored in single quotes, like $ & * ; |.'
It will give this:
All sorts of things are ignored in single quotes, like $ & * ; |.
The only thing that cannot be put within single quotes is a single quote.
Double quotes act similarly to single quotes, except double quotes still allow the shell to interpret dollar signs, back quotes and backslashes. It is already known that backslashes prevent a single special character from being interpreted. This can be useful within double quotes if a dollar sign needs to be used as text instead of for a variable. It also allows double quotes to be escaped so they are not interpreted as the end of a quoted string.
echo "Here's how we can use single ' and double \" quotes within double quotes"
It will give this:
Here's how we can use single ' and double " quotes within double quotes
It may also be noticed that the apostrophe, which would otherwise be interpreted as the beginning of a quoted string, is ignored within double quotes. Variables, however, are interpreted and substituted with their values within double quotes.
echo "The current Oracle SID is $ORACLE_SID"
It will give this:
The current Oracle SID is test
Back quotes are wholly unlike single or double quotes. Instead of being used to prevent the interpretation of special characters, back quotes actually force the execution of the commands they enclose. After the enclosed commands are executed, their output is substituted in place of the back quotes in the original line. This will be clearer with an example.
today=`date '+%A, %B %d, %Y'`
echo $today
It will give this:
Monday, September 28, 2015

Since this is the de facto answer when dealing with quotes in Bash, I'll add upon one more point missed in the answers above, when dealing with the arithmetic operators in the shell.
The Bash shell supports two ways to do arithmetic operation, one defined by the built-in let command and the other the $((..)) operator. The former evaluates an arithmetic expression while the latter is more of a compound statement.
It is important to understand that the arithmetic expression used with let undergoes word-splitting, pathname expansion just like any other shell commands. So proper quoting and escaping need to be done.
See this example when using let:
let 'foo = 2 + 1'
echo $foo
3
Using single quotes here is absolutely fine here, as there isn't any need for variable expansions here. Consider a case of
bar=1
let 'foo = $bar + 1'
It would fail miserably, as the $bar under single quotes would not expand and needs to be double-quoted as
let 'foo = '"$bar"' + 1'
This should be one of the reasons, the $((..)) should always be considered over using let. Because inside it, the contents aren't subject to word-splitting. The previous example using let can be simply written as
(( bar=1, foo = bar + 1 ))
Always remember to use $((..)) without single quotes
Though the $((..)) can be used with double quotes, there isn't any purpose to it as the result of it cannot contain content that would need the double quote. Just ensure it is not single quoted.
printf '%d\n' '$((1+1))'
-bash: printf: $((1+1)): invalid number
printf '%d\n' $((1+1))
2
printf '%d\n' "$((1+1))"
2
Maybe in some special cases of using the $((..)) operator inside a single quoted string, you need to interpolate quotes in a way that the operator either is left unquoted or under double quotes. E.g., consider a case, when you are tying to use the operator inside a curl statement to pass a counter every time a request is made, do
curl http://myurl.com --data-binary '{"requestCounter":'"$((reqcnt++))"'}'
Notice the use of nested double quotes inside, without which the literal string $((reqcnt++)) is passed to the requestCounter field.

There is a clear distinction between the usage of ' ' and " ".
When ' ' is used around anything, there is no "transformation or translation" done. It is printed as it is.
With " ", whatever it surrounds, is "translated or transformed" into its value.
By translation/ transformation I mean the following:
Anything within the single quotes will not be "translated" to their values. They will be taken as they are inside quotes. Example: a=23, then echo '$a' will produce $a on standard output. Whereas echo "$a" will produce 23 on standard output.

A minimal answer is needed for people to get going without spending a lot of time as I had to.
The following is, surprisingly (to those looking for an answer), a complete command:
$ echo '\'
whose output is:
\
Backslashes, surprisingly to even long-time users of bash, do not have any meaning inside single quotes. Nor does anything else.

Related

RegEx match is not working if it contains $

The following match returns false. How can I change the regular expression to correct it?
"hello$world" -match '^hello$(wo|ab).*$'
"hello$abcde" -match '^hello$(wo|ab).*$'
'hello$world' -match '^hello\$(wo|ab).*$'
'hello$abcde' -match '^hello\$(wo|ab).*$'
You need to quote the left hand side with single quotes so $world isn't treated like variable interpolation. You need to escape the $ in the right hand side so it isn't treated as end of line.
From About Quoting Rules:
When you enclose a string in double quotation marks (a double-quoted string), variable names that are preceded by a dollar sign ($) are replaced with the variable's value before the string is passed to the command for processing.
...
When you enclose a string in single-quotation marks (a single-quoted string), the string is passed to the command exactly as you type it. No substitution is performed.
From About Regular Expressions:
The two commonly used anchors are ^ and $. The carat ^ matches the start of a string, and $, which matches the end of a string. This allows you to match your text at a specific position while also discarding unwanted characters.
...
Escaping characters
The backslash \ is used to escape characters so they are not parsed by the regular expression engine.
The following characters are reserved: []().\^$|?*+{}.
You will need to escape these characters in your patterns to match them in your input strings.

Why does q/\\a/ equal q/\a/?

The following example prints "SAME":
if (q/\\a/ eq q/\a/) {
print "SAME\n";
}
else {
print "DIFFERENT\n";
}
I understand this is consistent with the documentation. But I think this behavior is undesirable. Is there a need to escape a backlash lilteral in single-quoted string? If I wanted 2 backlashes, I'd need to specify 4; this does not seem convenient.
Shouldn't Perl detect whether a backslash serves as an escape character or not? For instance, when a backslash does not precede a delimiter, it should be treated as a literal; and if that were the case, I wouldn't need 3 backslashes to express two, e.g.,
q<a\\b>
instead of
q<a\\\b>.
Is there a need to escape a backlash in single-quoted string?
Yes, if the backslash is followed by another backslash, or is the last character in the string:
$ perl -e'print q/C:\/'
Can't find string terminator "/" anywhere before EOF at -e line 1.
$ perl -e'print q/C:\\/'
C:\
This makes it possible to include any character in a single-quoted string, including the delimiter and the escape character.
If I wanted 2 backlashes, I'd need to specify 4; this does not seem convenient.
Actually, you only need three (because the second backslash isn't followed by another backslash). But as an alternative, if your string contains a lot of backslashes you can use a single-quoted heredoc, which requires no escaping:
my $path = <<'END';
C:\a\very\long\path
END
chomp $path;
print $path; # C:\a\very\long\path
Note that the heredoc adds a newline to the end, which you can remove with chomp.
In single-quoted string literals,
A backslash represents a backslash unless followed by the delimiter or another backslash, in which case the delimiter or backslash is interpolated.
In other words,
You must escape delimiters.
You must escape \ that are followed by \ or the delimiter.
You may escape \ that aren't followed by \ or the delimiter.
So,
q/\// ⇒ /
q/\\\\a/ ⇒ \\a
q/\\\a/ ⇒ \\a
q/\\a/ ⇒ \a
q/\a/ ⇒ \a
Is there a need to escape a backlash in single-quoted string?
Yes, if it's followed by another backslash or the delimiter.
If I wanted 2 backlashes, I'd need to specify 4
Three would suffice.
this does not seem convenient.
It's more convenient than double-quoted strings, where backslashes must always be escaped. Single-quoted string require the minimum amount of escaping possible without losing the ability to produce the delimiter.

Cannot include space in string in one line program mode for Perl on Windows?

The command
perl -ne "print "" """ AnyTextFile.txt
running on Windows with latest ActivePerl installed (5.020) complains Can't find string terminator '"' anywhere before EOF at -e line 1.. Other characters or variables work as expected, like
perl -ne "print ""$.-$_""" AnyTextFile.txt
I checked that double quotes are passed to perl as expected, even if it is a little weird when escape double quotes in cmd.exe. Why space cannot be shown in the above double quoted string? Using single quote could work but it loses variables interpolation functionality.
perl -ne "print \" \"" AnyTextFile.txt
Why?
A lot of programs get its arguments by means of the standard argument parser used by the C library initially used to compile the language itself, its libraries or used as a base.
For windows, in general, the "rules" for argument parsing are
Arguments are delimited by white space, which is either a space or a tab.
A string surrounded by double quotation marks is interpreted as a
single argument, regardless of white space contained within. A quoted
string can be embedded in an argument. Note that the caret (^) is not
recognized as an escape character or delimiter.
A double quotation mark preceded by a backslash, \", is interpreted as
a literal double quotation mark (").
Backslashes are interpreted literally, unless they immediately precede
a double quotation mark.
If an even number of backslashes is followed by a double quotation
mark, then one backslash () is placed in the argv array for every
pair of backslashes (\), and the double quotation mark (") is
interpreted as a string delimiter.
If an odd number of backslashes is followed by a double quotation
mark, then one backslash () is placed in the argv array for every
pair of backslashes (\) and the double quotation mark is interpreted
as an escape sequence by the remaining backslash, causing a literal
double quotation mark (") to be placed in argv.

Fix improper quotes in text

I receive text from some writers that has a string like: string "string "string.
I want it to read string "string" string.
I've tried various sed tricks but none work.
Here is one failed attempt:
sed 's/.* "/.*"/g'
Your attempt fails for multiple reasons.
The wildcard .* will consume as much as it can in the string, meaning it will only ever allow a single substitution to happen (the final double quote in the string).
You cannot use .* in the substitution part -- what you substitute with is just a string, not a regular expression. The way to handle "whatever (part of) the regex matched" is through backreferences.
So here is a slightly less broken attempt:
sed 's/"\([^"]*\) "/"\1"/g' file
This will find a double quote, then find and capture anything which is not a double quote, then find a space and a double quote; and substitute the entire match with a double quote, the first captured expression (aka back reference, or backref), and another double quote. This should fix strings where the only problem is a number of spaces inside the closing double quotes, but not missing whitespace after the closing double quote, nor strings with leading spaces inside the double quotes or unpaired double quotes.
The lack of spaces after can easily be added;
sed 's/"\([^"]*\) " */"\1" /g;s/ $//' file
This will add a space after every closing double quote, and finally trim any space at end of line to fix up this corner case.
Now, you could either try to update the regex for leading spaces, or just do another pass with a similar regex for those. I would go with the latter approach, even though the former is feasible as well (but will require a much more complex regex, and the corner cases are harder to keep in your head).
sed 's/"\([^"]*\) " */"\1" /g;s/ $//;
s/ *" \([^"]*\)"/ "\1"/g;s/^ //' file
This will still fail for inputs with unbalanced double quotes, which are darn near impossible to handle completely automatically anyway (how do you postulate where to add a missing double quote?)
This may work for some cases but may fail with unbalanced quotes:
sed 's/"\([^"]*\S\)\s\s*"/"\1"/g'
to also add space after a quoted phrase, if a space is missing:
sed -e 's/"\([^"]*\S\)\s\s*"/"\1"/g' -e 's/\("[^"]*"\)\([^"]\)/\1 \2/g'
Here is an awk solution:
echo 'string "string "string.' | awk -F' "' '{for (i=1;i<=NF;i++) printf (i%2==0?"\"":"")"%s"(i%2==0?"\"":"")(i!=NF?" ":""),$i;print ""}'
string "string" string.
It looks at numbers of quotes, and every second quotes should be behind text.

Perl system access denied

I'm running the following on a windows machine as an administrator
system("tracert 192.168.63.1 > d:\netmon\test.txt");
the output is Access Denied. Running the tracert without creating the file works fine. So Why can't I create the file in the existing netmon directory. I have full access to that directory.
Can somebody point me in the right direction. Thanks
In Perl, the backslash (\) is a special character inside of double quotes, used to "escape" other special characters or to specify other untypeable characters. The sequences "\n" and "\t", which are contained in your example, are used to produce the newline and the tab character, respectively.
To produce a literal backslash character inside of double quotes, we use two consecutive backslash characters, so:
system("tracert 192.168.63.1 > d:\\netmon\\test.txt");
will produce the results you want.
Perl treats strings enclosed by single quotes ('') differently from double quotes. Inside single quotes, \ is not a special character (well actually, it is still a little bit special, but a lot less special than inside double quotes), so you could also have written your expression as:
system('tracert 192.168.63.1 > d:\netmon\test.txt');
If you use \ in your path, you need to double up:
system("tracert 192.168.63.1 > d:\\netmon\\test.txt");
Or you could just use a slash instead:
system('tracert 192.168.63.1 > d:/netmon/test.txt');