How do I store up to 2 names into my variables if needed and also how do I escape a possible single quote in a name? - bash

PhoneBook.txt has names delimited by :
ex= first:last:number - simple
ex= first first:last last:number - 2 firstnames and/or 2 last names
ex= f'irst:l'ast:number - first name or last name with a single quote in it.
My current script
#!/bin/bash
firstName="$1"
lastName="$2"
if [[ "$firstName" == "" ]]; then
read -p "Please enter a first name: " firstName
fi
if [[ "$lastName" == "" ]]; then
read -p "Please enter a last name: " lastName
fi
grep "$firstName:$lastName" PhoneBook.txt

The -F argument tells grep to search for a fixed string instead of a regex.

Use double quotes to delimit your arguments on the command line, e.g.:
./phonebook "first1 first2" "last o'last"
You're free to use single quotes in a double-quoted string.
Just be aware that double-quoted strings are subject to parameter (variable) and command substitution, so instances of literal $ chars. must be escaped as \$.
Similarly, embedded double quotes must be escaped as \".
Note that, by contrast, there is no direct way to embed single quotes in a single-quoted string - you have to break the string apart and insert an escaped single quote, \'; e.g., to single-quote isn't, use 'isn'\''t'; however, you can freely embed double quotes.

Related

How to concatenate string variables that contain space? [duplicate]

How can I escape double quotes inside a double string in Bash?
For example, in my shell script
#!/bin/bash
dbload="load data local infile \"'gfpoint.csv'\" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY \"'\n'\" IGNORE 1 LINES"
I can't get the ENCLOSED BY '\"' with double quote to escape correctly. I can't use single quotes for my variable, because I want to use variable $dbtable.
Use a backslash:
echo "\"" # Prints one " character.
A simple example of escaping quotes in the shell:
$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc
It's done by finishing an already-opened one ('), placing the escaped one (\'), and then opening another one (').
Alternatively:
$ echo 'abc'"'"'abc'
abc'abc
$ echo "abc"'"'"abc"
abc"abc
It's done by finishing already opened one ('), placing a quote in another quote ("'"), and then opening another one (').
More examples: Escaping single-quotes within single-quoted strings
Keep in mind that you can avoid escaping by using ASCII codes of the characters you need to echo.
Example:
echo -e "This is \x22\x27\x22\x27\x22text\x22\x27\x22\x27\x22"
This is "'"'"text"'"'"
\x22 is the ASCII code (in hex) for double quotes and \x27 for single quotes. Similarly you can echo any character.
I suppose if we try to echo the above string with backslashes, we will need a messy two rows backslashed echo... :)
For variable assignment this is the equivalent:
a=$'This is \x22text\x22'
echo "$a"
# Output:
This is "text"
If the variable is already set by another program, you can still apply double/single quotes with sed or similar tools.
Example:
b="Just another text here"
echo "$b"
Just another text here
sed 's/text/"'\0'"/' <<<"$b" #\0 is a special sed operator
Just another "0" here #this is not what i wanted to be
sed 's/text/\x22\x27\0\x27\x22/' <<<"$b"
Just another "'text'" here #now we are talking. You would normally need a dozen of backslashes to achieve the same result in the normal way.
Bash allows you to place strings adjacently, and they'll just end up being glued together.
So this:
echo "Hello"', world!'
produces
Hello, world!
The trick is to alternate between single and double-quoted strings as required. Unfortunately, it quickly gets very messy. For example:
echo "I like to use" '"double quotes"' "sometimes"
produces
I like to use "double quotes" sometimes
In your example, I would do it something like this:
dbtable=example
dbload='load data local infile "'"'gfpoint.csv'"'" into '"table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"'"'"' LINES "'TERMINATED BY "'"'\n'"'" IGNORE 1 LINES'
echo $dbload
which produces the following output:
load data local infile "'gfpoint.csv'" into table example FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "'\n'" IGNORE 1 LINES
It's difficult to see what's going on here, but I can annotate it using Unicode quotes. The following won't work in Bash – it's just for illustration:
dbload=‘load data local infile "’“'gfpoint.csv'”‘" into ’“table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '”‘"’“' LINES ”‘TERMINATED BY "’“'\n'”‘" IGNORE 1 LINES’
The quotes like “ ‘ ’ ” in the above will be interpreted by bash. The quotes like " ' will end up in the resulting variable.
If I give the same treatment to the earlier example, it looks like this:
echo “I like to use” ‘"double quotes"’ “sometimes”
Store the double quote character in a variable:
dqt='"'
echo "Double quotes ${dqt}X${dqt} inside a double quoted string"
Output:
Double quotes "X" inside a double quoted string
Check out printf...
#!/bin/bash
mystr="say \"hi\""
Without using printf
echo -e $mystr
Output: say "hi"
Using printf
echo -e $(printf '%q' $mystr)
Output: say \"hi\"
Make use of $"string".
In this example, it would be,
dbload=$"load data local infile \"'gfpoint.csv'\" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY \"'\n'\" IGNORE 1 LINES"
Note (from the man page):
A double-quoted string preceded by a dollar sign ($"string") will cause the string to be translated according to the current locale. If the current locale is C or POSIX, the dollar sign is ignored. If the string is translated and replaced, the replacement is double-quoted.
For use with variables that might contain spaces in you Bash script, use triple quotes inside the main quote, e.g.:
[ "$(date -r """$touchfile""" +%Y%m%d)" -eq "$(date +%Y%m%d)" ]
Add "\" before double quote to escape it, instead of \
#! /bin/csh -f
set dbtable = balabala
set dbload = "load data local infile "\""'gfpoint.csv'"\"" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"\""' LINES TERMINATED BY "\""'\n'"\"" IGNORE 1 LINES"
echo $dbload
# load data local infile "'gfpoint.csv'" into table balabala FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "''" IGNORE 1 LINES

printing value from variable returning the existing paths using '*' unix

how could I print a variable that has '*', I just want to print value and is taking it as "all"
example of what I want:
var=/home/us*r/
echo ${var}
Result:
/home/us*r/
example of what is doing
var=/home/us*r/
echo ${var}
Result:
/home/user/
/home/usar/
/home/usir/
any idea of how to print just the value of variable?
Put the variable expansion in double quotes:
echo "$var"
Curly braces are optional and they help if you want to interpolate a variable expansion in a string where it's surrounded by a character that's valid in a variable name, e.g.: echo "${var}_$var2", but it's double quotes that supress pathname expansion and field splitting.
See the Word Expansion section of dash(1) for more details.

UNIX: Using a regex that matches either single or double quotes with grep

I have a string say
string="MYSTRING"
Now I want to grep for any occurrence of "MYSTRING" (with double quotes) such that there must be parentheses at starting, basically I want to search, in which places "MYSTRING" is used as function's parameter. So,
foo( "MYSTRING" //postive
foo("MYSTRING" //positive
foo('MYSTRING' //positive
foo( 'MYSTRING' //positive
var a = "MYSTRING" //negative
I used:
string="MYSTRING"
regexstring="[(]*\"$string\""
grep -e "$regexString" <<'EOF'
foo( "MYSTRING" //postive
foo("MYSTRING" //positive
foo('MYSTRING' //positive
foo( 'MYSTRING' //positive
var a = "MYSTRING" //negative
EOF
Ideally, all the items with "positive" next to them and none of the items with "negative" will match. What needs to change to make that happen?
The easy way to do this is to use the ksh extension (adopted by bash) $'' to provide a literal string that can include backticks.
#!/usr/bin/env bash
string=MYSTRING
regexstring=$'[(][[:space:]]*[\'"]'"$string"$'[\'"]'
grep -e "$regexstring" "$#"
Breaking down this assignment:
$'[(][[:space:]]*[\'"]'
...is a string literal which evaluates to the following:
[(][[:space:]]*['"]
...thus, it matches a single (, followed by zero or more spaces, followed by either ' or ".
The second part of it is a double-quoted expansion, "$string"; this should be fairly straight on its face.
The final part is $'[\'"']'; just as in the first part, the $'' string-literal syntax is used to generate a string that can contain both ' and " as contents.
By the way -- in POSIX sh, this might instead look like:
regexstring='[(][[:space:]]*['"'"'"]'"$string""['"'"]'
There, we're using single-quoted strings to hold literal double quotes, and double-quoted strings to hold literal single quotes.

Replace " " with "\ " in a file path string with variable expansion

I know there is a better way to do this.
What is the better way?
How do you do a string replace on a string variable in bash?
For Example: (using php because that's what I know)
$path = "path/to/directory/foo bar";
$path = str_replace(" ", "\ ", "$path");
echo $path;
returns:
path/to/directory/foo\ bar
To perform the specific replacement in bash:
path='path/to/directory/foo bar'
echo "${path// /\\ }"
Don't use prefix $ when assigning to variables in bash.
No spaces are allowed around the =.
Note that path is assigned with single quotes, whereas the string replacement occurs in double quotes - this distinction is important: bash does NOT interpret single-quoted strings, whereas you can refer to variables (and do other things) in double-quoted strings; (also, not quoting a variable reference at all has other ramifications, often undesired - in general, double-quote your variable references)
Explanation of string replacement "${path// /\\ }":
In order to perform value substitution on a variable, you start with enclosing the variable name in {...}
// specifies that ALL occurrences of the following search pattern are to be replaced (use / to replace the first occurrence only).
/ separates the search pattern, (a single space), from the replacement string, \\ .
The replacement string, \ , must be represented as \\ , because \ has special meaning as an escape char. and must therefore itself be escaped for literal use.
The above is an instance of what bash (somewhat cryptically) calls shell parameter expansion and also parameter expansion and [parameter and] variable expansion. There are many more flavors, such as for extracting a substring, providing a default value, stripping a prefix or suffix, ... - see the BashGuide page on the topic or the manual.
As for what types of expressions are supported in the search and replacement strings:
The search expression is a globbing pattern of the same type used in filename expansion (e.g, *.txt); for instance, v='dear me'; echo "${v/m*/you}" yields 'dear you'. Note that the longest match will be used.
Additionally, the first character of the pattern has special meaning in this context:
/, as we've seen above, causes all matching occurrences of the pattern to be replaced - by default, only the first one is replaced.
# causes the rest of the pattern to only match at the beginning of the input variable
% only matches at the end
The replacement expression is a string that is subject to shell expansions; while there is no support for backreferences, the fact that the string is expanded allows you to have the replacement string reference other variables, contain commands, with $(...), ...; e.g.:
v='sweet home'; echo "${v/home/$HOME}" yields, for instance, 'sweet /home/jdoe'.
v='It is now %T'; echo "${v/\%T/$(date +%T)}" yields, for instance, It is now 10:05:17.
o1=1 o2=3 v="$o1 + $o2 equals result"; echo "${v/result/$(( $o1 + $o2 ))}" yields '1 + 3 equals 4' (I think)
There are many more features and subtleties - refer to the link above.
How about sed? Is that what you're looking for?
#!/bin/bash
path="path/to/directory/foo bar"
new_path=$(echo "$path" | sed 's/ /\\ /g')
echo "New Path: '$new_path"
But as #n0rd pointed out in his comment, is probably better just quoting the path when you want to use it; something like...
path="path/to/directory/foo bar"
echo "test" > "$path"

How can I escape a double quote inside double quotes?

How can I escape double quotes inside a double string in Bash?
For example, in my shell script
#!/bin/bash
dbload="load data local infile \"'gfpoint.csv'\" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY \"'\n'\" IGNORE 1 LINES"
I can't get the ENCLOSED BY '\"' with double quote to escape correctly. I can't use single quotes for my variable, because I want to use variable $dbtable.
Use a backslash:
echo "\"" # Prints one " character.
A simple example of escaping quotes in the shell:
$ echo 'abc'\''abc'
abc'abc
$ echo "abc"\""abc"
abc"abc
It's done by finishing an already-opened one ('), placing the escaped one (\'), and then opening another one (').
Alternatively:
$ echo 'abc'"'"'abc'
abc'abc
$ echo "abc"'"'"abc"
abc"abc
It's done by finishing already opened one ('), placing a quote in another quote ("'"), and then opening another one (').
More examples: Escaping single-quotes within single-quoted strings
Keep in mind that you can avoid escaping by using ASCII codes of the characters you need to echo.
Example:
echo -e "This is \x22\x27\x22\x27\x22text\x22\x27\x22\x27\x22"
This is "'"'"text"'"'"
\x22 is the ASCII code (in hex) for double quotes and \x27 for single quotes. Similarly you can echo any character.
I suppose if we try to echo the above string with backslashes, we will need a messy two rows backslashed echo... :)
For variable assignment this is the equivalent:
a=$'This is \x22text\x22'
echo "$a"
# Output:
This is "text"
If the variable is already set by another program, you can still apply double/single quotes with sed or similar tools.
Example:
b="Just another text here"
echo "$b"
Just another text here
sed 's/text/"'\0'"/' <<<"$b" #\0 is a special sed operator
Just another "0" here #this is not what i wanted to be
sed 's/text/\x22\x27\0\x27\x22/' <<<"$b"
Just another "'text'" here #now we are talking. You would normally need a dozen of backslashes to achieve the same result in the normal way.
Bash allows you to place strings adjacently, and they'll just end up being glued together.
So this:
echo "Hello"', world!'
produces
Hello, world!
The trick is to alternate between single and double-quoted strings as required. Unfortunately, it quickly gets very messy. For example:
echo "I like to use" '"double quotes"' "sometimes"
produces
I like to use "double quotes" sometimes
In your example, I would do it something like this:
dbtable=example
dbload='load data local infile "'"'gfpoint.csv'"'" into '"table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"'"'"' LINES "'TERMINATED BY "'"'\n'"'" IGNORE 1 LINES'
echo $dbload
which produces the following output:
load data local infile "'gfpoint.csv'" into table example FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "'\n'" IGNORE 1 LINES
It's difficult to see what's going on here, but I can annotate it using Unicode quotes. The following won't work in Bash – it's just for illustration:
dbload=‘load data local infile "’“'gfpoint.csv'”‘" into ’“table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '”‘"’“' LINES ”‘TERMINATED BY "’“'\n'”‘" IGNORE 1 LINES’
The quotes like “ ‘ ’ ” in the above will be interpreted by bash. The quotes like " ' will end up in the resulting variable.
If I give the same treatment to the earlier example, it looks like this:
echo “I like to use” ‘"double quotes"’ “sometimes”
Store the double quote character in a variable:
dqt='"'
echo "Double quotes ${dqt}X${dqt} inside a double quoted string"
Output:
Double quotes "X" inside a double quoted string
Check out printf...
#!/bin/bash
mystr="say \"hi\""
Without using printf
echo -e $mystr
Output: say "hi"
Using printf
echo -e $(printf '%q' $mystr)
Output: say \"hi\"
Make use of $"string".
In this example, it would be,
dbload=$"load data local infile \"'gfpoint.csv'\" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY \"'\n'\" IGNORE 1 LINES"
Note (from the man page):
A double-quoted string preceded by a dollar sign ($"string") will cause the string to be translated according to the current locale. If the current locale is C or POSIX, the dollar sign is ignored. If the string is translated and replaced, the replacement is double-quoted.
For use with variables that might contain spaces in you Bash script, use triple quotes inside the main quote, e.g.:
[ "$(date -r """$touchfile""" +%Y%m%d)" -eq "$(date +%Y%m%d)" ]
Add "\" before double quote to escape it, instead of \
#! /bin/csh -f
set dbtable = balabala
set dbload = "load data local infile "\""'gfpoint.csv'"\"" into table $dbtable FIELDS TERMINATED BY ',' ENCLOSED BY '"\""' LINES TERMINATED BY "\""'\n'"\"" IGNORE 1 LINES"
echo $dbload
# load data local infile "'gfpoint.csv'" into table balabala FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY "''" IGNORE 1 LINES

Resources