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

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.

Related

How do bash variable types work and how to work around automatic interpretation?

I am trying to set up a variable that contains a string representation of a value with leading zeroes. I know I can printf to terminal the value, and I can pass the string output of printf to a variable. It seems however that assigning the value string to a new variable reinterprets the value and if I then print it, the value has lost its leading zeroes.
How do we work with variables in bash scripts to avoid implicit type inferences and ultimately how do I get to the solution I'm looking for. FYI I'm looking to concatenate a large fixed length string numeric, something like a part number, and build it from smaller prepared strings.
Update:
Turns out exactly how variables are assigned changes their interpretation in some way, see below:
Example:
#!/bin/bash
a=3
b=4
aStr=$(printf %03d $a)
bStr=$(printf %03d $b)
echo $aStr$bStr
output
$ ./test.sh
003004
$
Alternate form:
#!/bin/bash
((a = 3))
((b = 4))
((aStr = $(printf %03d $a)))
((bStr = $(printf %03d $b)))
echo $aStr$bStr
output
$ ./test.sh
34
$
How do bash variable types
There are no variable types. All variables are strings (type).. Variables store a value (a string), but also variables have some additional magic attributes associated with them.
There are Bash arrays, but I think it's an attribute that a variable is an array. Still, in any case, every array element holds a string. There is a "numeric" variable declare -i var, but it's attribute of the variable - in memory, the variable is still a string, only when setting it Bash checks if the string (still a string!) to be set is a number.
assigning the value string to a new variable reinterprets the value
Bash does not "interpret" the value on assignment.
How do we work with variables in bash scripts to avoid implicit type inferences
There are no "type inferences". The type of variable does not change - it holds a string.
The value of the variable undergoes different expansions and conversions depending on the context where it is used. For example $(...) removes trailing newlines. Most notably unquoted variable expansions undergo word splitting and filename expansion.
Example:
Posting your code to shellcheck results in:
Line 2:
a = 3
^-- SC2283 (error): Remove spaces around = to assign (or use [ ] to compare, or quote '=' if literal).
Line 3:
b = 4
^-- SC2283 (error): Remove spaces around = to assign (or use [ ] to compare, or quote '=' if literal).
Line 4:
aStr = $(printf %03d $a)
^-- SC2283 (error): Remove spaces around = to assign (or use [ ] to compare, or quote '=' if literal).
^-- SC2046 (warning): Quote this to prevent word splitting.
^-- SC2154 (warning): a is referenced but not assigned.
^-- SC2086 (info): Double quote to prevent globbing and word splitting.
Did you mean: (apply this, apply all SC2086)
aStr = $(printf %03d "$a")
Line 5:
bStr = $(printf %03d $b)
^-- SC2283 (error): Remove spaces around = to assign (or use [ ] to compare, or quote '=' if literal).
^-- SC2046 (warning): Quote this to prevent word splitting.
^-- SC2154 (warning): b is referenced but not assigned.
^-- SC2086 (info): Double quote to prevent globbing and word splitting.
Did you mean: (apply this, apply all SC2086)
bStr = $(printf %03d "$b")
Line 7:
echo $aStr$bStr
^-- SC2154 (warning): aStr is referenced but not assigned.
^-- SC2086 (info): Double quote to prevent globbing and word splitting.
^-- SC2154 (warning): bStr is referenced but not assigned.
^-- SC2086 (info): Double quote to prevent globbing and word splitting.
Did you mean: (apply this, apply all SC2086)
echo "$aStr""$bStr"
Shellcheck tells you what is wrong. After fixing the problems:
#!/bin/bash
a=3
b=4
aStr=$(printf %03d "$a")
bStr=$(printf %03d "$b")
echo "$aStr$bStr"
Which upon execution outputs your expected output:
003004
By doing ((aStr = $(printf %03d $a))), you are destroying again the careful formatting done by printf. You would see the same effect if you do a
(( x = 005 ))
echo $x
which outputs 5.
Actually the zeroes inserted by printf could do harm to your number, as you see by the following example:
(( x = 015 ))
echo $x
which outputs 13, because the ((....)) interprets the leading zero as an indication for octal numbers.
Hence, if you have a string representing a formatted (pretty-printed) number, don't use this string in numeric context anymore.

bash - brace expansion not expanding?

On Kubuntu 15.10
echo $BASH_VERSION
4.3.42(1)-release
I try
reps=1
threads={1}{10..60..10}
for((r=0;r<$reps;r++))
do
tCount=0
for t in $threads
do
echo "t=$t, tCount=${tCount}"
#do something funny with it
((tCount++))
done
done
and it produces a single line
t={1}{10..60..10}, tCount=0
How do I get this to work?
edit
I expect
t=1, tCount=0
t=10, tCount=1
t=20, tCount=2
t=30, tCount=3
t=40, tCount=4
t=50, tCount=5
t=60, tCount=6
update
note that threads=({1}{10..60..10})
and then for t in ${threads[#]}
will prefix the 10..60..10 range with the string {1}
(i.e. {1}10,{1}20,..,{1}60 )
The {1} expression is just a string, since it doesn't conform to the brace expansion syntax:
A sequence expression takes the form {X..Y[..INCR]}, where X and Y are either integers or single characters, and INCR, an optional increment, is an integer.
The brace expansion is performed before variable expansion, so you can't expand braces by just referring to a variable:
The order of expansions is: brace expansion; tilde expansion, parameter and variable expansion, arithmetic expansion, and command substitution (done in a left-to-right fashion); word splitting; and filename expansion.
Whether write the brace expansion directly, or use eval (usually not recommended).
Example:
tCount=0
for t in {1,{10..60..10}}; do
echo "t=$t tCount=$tCount"
(( tCount++ ))
done

How bash eval expansion work for single qoute double qoute

Someone please help to explain how this work? About the single quote it should not interpret anything but it is not working as what i expected. I expect to get echo $testvar value exactly '"123b"'.
a="testvar"
b="'"123b"'"
eval $a='$b'
echo $testvar
'123b'
a="testvar"
b='"123b"'
eval $a='$b'
echo $testvar
"123b"
a="testvar"
b='"123b"'
eval $a=$b
echo $testvar
123b
Guessing that you want testvar to be <single-quote><double-quote>123b<double-quote><single-quote>:
testvar=\'\"123b\"\'
Consider this in C or Java:
char* str = "123b";
printf("%s\n", str);
String str = "123b";
System.out.println(str);
Why does this write 123b when we clearly used double quotes? Why doesn't it write "123b", with quotes?
The answer is that the quotes are not part of the data. The quotes are used by the programming language to determine where strings start and stop, but they're not in any way part of the string. This is just as true for Bash as for C and Java.
Just like there's no way in Java to differentiate Strings created with "123" + "b" and "123b", there's no way in Bash to tell that b='"123b"' used single quotes in its definition, as opposed to e.g. b=\"123b\".
If given a variable you want to assign its value surrounded by single quotes, you can use e.g.
printf -v testvar "'%s'" "$b"
But this just adds new literal single quotes around a string. It doesn't and cannot care how b was originally quoted, because that information is stored.
To instead add a layer of escaping to a variable, so that when evaluated once it turns into a literal string identical to your input, you can use:
printf -v testvar "%q" "$b"
This will produce a value which is quoted equivalently but not necessarily identically to your original definition. For "value" (a literal with double quotes in it), it may produce \"value\" or '"value"' or '"'value'"' which all evaluate exactly to "value".

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 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?

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.

Resources