Bash Script - Exclamation Point within Variable Reference - bash

I'm looking over a script (which has been used successfully in the past) which contains the following:
node=1
while :
do
userKey=WEB_${node}_USER
userVal=`echo ${!userKey}`
I have not been able to figure out why an exclamation point would be added to a variable reference like this. What purpose does "!" serve in this context?
It's rare for me to do much scripting so if I am missing any details please let me know and I will try to provide more information. I have not been able to find this answer elsewhere.
Thanks in advance!

It's called indirect parameter expansion. Where $userKey expands to the value of the variable userKey, ${!userKey} expands to the value of the variable whose name is the value of userKey. Since usrKey has the value WEB_1_USER (given the current value of $node, ${!userKey} expands to the same result as $WEB_1_USER.
Its use is somewhat rare, since in many cases (including, it appears, here) an array WEB_USER of user names would be clearer than a set of numbered variables.
WEB_USER=(alice bob charlie)
node=1
while :
do
userVal=${WEB_USER[node]}

In bash, I thought that the only characters that retained their meta-character status inside double quotes were the dollar sign ($), the back-tick (`) and the backslash (\).

Related

Replacing (escaping) characters in Groovy

For a gradle script, I am composing strings that will be used as command line for a subsequent gradle Test-task. One of the strings is the user's password, which eventually will be passed to the called (exec'ed) "java ..." call using the JVM's -D option, e.g. -Dpassword=foobar.
What complicates things here is, that this password can/should of course contain special characters, that may interfere with the use of the string as command line. In other words: I need to escape special characters (which is OS-specific). :-(
Now to my actual question:
I want to use the String.replaceAll method, i.e. replaceAll(list_of_special characters, EscapeCharacter + Ref_to_matched_character),
e.g. simplified something like replaceAll("[#$%^&]", "^$1")
'^' meaning the escape character and '$1' meaning the matched character here.
Is that possible, i.e. can one refer to the matched pattern in the second argument of replaceAll?
Is that possible, i.e. can one refer to the matched pattern in the second argument of replaceAll?
yes, it's possible
'a#b$c'.replaceAll('([#$%^&])', '^$1')
returns
a^#b^$c
Thanks for the responses and the reviews improving readability. Meanwhile I got my expression working. For those interested:
// handles gthe following: `~!##$%^&*()_+-={}|[]\:;"'<>?,./
escaped = original.replaceAll('[~!##\\$\\%\\^\\&\\*\\(\\)_\\+-={}\\|\\[\\]\\\\:;\"\\\'<>\\?,\\./]', '^$0') // for Windows - cmd.exe

Creating a string that calls a variable

I could use some suggestions, this probably isn't the most elegant way to do this but it's what came to mind. Let me add a couple snippets for clarity.
week1="01-\(04\|05\|06\|07\|08\|09\|10\)-2016"
week2="01-\(11\|12\|13\|14\|15\|16\|17\)-2016"
week3="01-\(18\|19\|20\|21\|22\|23\|24\)-2016"
week4="01-\(25\|26\|27\|28\|29\|30\|31\)-2016"
week5="02-\(01\|02\|03\|04\|05\|06\|07\)-2016"
I have a text file that has dates in each line, for example
293232343;01-02-2016;blah;more blah
234872348;02-01-2016;blah;extra blah
I am trying to create a loop so I can grab different data depending on the calendar week.
current_week=`date +%W`
for (( c=1; c<=$current_week; c++ ))
do
sort -k2 archive.txt|tr "\\t" ";"|grep $week$c|while read line; do
My problem is that $week$c doesn't actually translate to $week1, $week2, etc. Any easy solutions here? Thanks in advance.
From man bash:
If the first character of parameter is an exclamation point, a level
of
variable indirection is introduced. Bash uses the value of the vari-
able formed from the rest of parameter as the name of the variable;
this variable is then expanded and that value is used in the rest of
the substitution, rather than the value of parameter itself. This is
known as indirect expansion. The exceptions to this are the expansions
of ${!prefix*} and ${!name[#]} described below. The exclamation point
must immediately follow the left brace in order to introduce indirec-
tion.
Then, what you need is
var="week$c"
... grep "${!var}" ...

Why bash indirect expansion has to use temp variable?

From https://stackoverflow.com/a/10820494/1764881, I know that the standard way of doing it seems to be:
var="SAMPLE$i"
echo ${!var}
But, I can't seem to do any of these following forms. They all failed:
echo ${!SAMPLE$i}
echo ${!"SAMPLE$i"}
I read the bash man page, but I still couldn't understand. Is it true that the first form is the only form accepted?
Yes. The underlying logic is that all parameter expansions take a single, literal word as the name of the parameter to expand, and any additional operator does something to the result. ! is no exception; var is expanded as usual, but the result is expanded again.
(As an aside, even arrays follow this rule. It might seem that something like ${array[2]%foo} applies two operators to array, but really array[2] is treated as the name of a single parameter. There is a little difference, as the index is allowed to be an arbitrary arithmetic expression rather than a literal number.)
(And for completeness, I should mention the actual exceptions, ${!prefix*} and ${!name[*]}, which confusingly use the same operator ! for querying variables themselves. The first lists variable names starting with the same prefix; the second lists the keys of the named array.)

ksh difference between $ and ${}

Can someone explain to me what is the difference, in Korn shell, between:
ANOTHER_VAR=${SOME_VAR}
and
ANOTHER_VAR=$SOME_VAR
I came across these types of declaration and can't see what the difference is.
One has two brace characters around the name and the other doesn't; otherwise, in this context, there is no difference.
However, if you had:
ONE_VAR="$TWO_VAR_$THREE_VAR"
UNO_VAR="${TWO_VAR}_${THREE_VAR}"
then the values in $ONE_VAR and $UNO_VAR will be different unless both $TWO_VAR and $TWO_VAR_ exist and $TWO_VAR_ holds the value that is stored in $TWO_VAR plus a trailing underscore (where $TWO_VAR could be an empty string, or undefined, as long as $TWO_VAR_ holds just an underscore).
Thanks to William Pursell for pointing out a minor inaccuracy in the previous version.
There are many contexts where you must use the braces, such as:
UNE_VAR=${YET_ANOTHER_VAR:-"default setting"}

Bash Variable escape character

I'm attempting to generate a url using a bunch of different variables however when I follow a variable with an underscore the variable after the underscore does not show up. However, if I put a space before the underscore then there is a space in the generated URL. So my question is, is there an escape character for doing the sort of thing I have described?
Also code:
URL="$baseURL$BUILD/TorBrowserBundle-$BUILD-$OS$BIT _$LANG.zip"
The issue occurs in between $BIT and $LANG.
you can use ${}
so something like
URL="${baseURL}${BUILD}/TorBrowserBundle-${BUILD}-${OS}${BIT}_${LANG}.zip"

Resources