This question already has answers here:
BASH regexp matching - including brackets in a bracketed list of characters to match against?
(4 answers)
Closed 5 years ago.
I need to match some variables defined in a config file against an input file in bash and replace the variable with config file input.
Config file
var1=value1
var2=value2
input file
My user value is [[var1]] and
some lines which does not have configuration variables
My client value is [[var2]]
some lines which does not have configuration variables
var1 and var2 in line 1 and 3 above must be replaced by the value in config file
rest of the lines remains same.
I am able to read config in an associative array say mapVals and input file to an array say inpArray.
Now when I am matching in a loop with below code.
for key in "${!mapVals[#]}"
do
match=\[\[$key\]\]
echo $match
let index=0
for line in "${inpArray[#]}"
do
if [[ $line =~ $match ]];
then
echo $line
fi
index=$(($index+1))
done
done
I am getting match for both line1 and line 3 for both of the [[var1]] and [[var2]] matches.
the output looks like
[[var1]]
My user value is [[var1]] and
My client value is [[var2]]
[[var2]]
My user value is [[var1]] and
My client value is [[var2]]
What should be the way for an exact match and replace.
Please comment if duplicate.
I got the answer here
so for square braces we need to use escape []
the regex for [[var1]] is => [\[][\[]var1]]
Related
How to read environmental variable in bash that contains spaces and possibly other characters that need to be escaped?
I have a file server.env
PUBLIC_KEY=ssh-rsa whatever+whatever+8whatever/whatever+p+whatever user#alans-MacBook-Pro.local
I am trying to read this file into bash script as an environmental variable:
export $(cat server.env | xargs)
I am getting an error:
-bash: export: `user#alans-MacBook-Pro.local': not a valid identifier
OK, trying to quote the value in server.env:
PUBLIC_KEY='ssh-rsa whatever+whatever+8whatever/whatever+p+whatever user#alans-MacBook-Pro.local'
the same error
Double quote:
PUBLIC_KEY="ssh-rsa whatever+whatever+8whatever/whatever+p+whatever user#alans-MacBook-Pro.local"
also errors
What am I missing here?
Bash provides parameter expansion with substring removal that will allow you to separate the NAME=value pairs read from the server.env file and then export the NAME=value pairs.
A simple read loop is all you need:
#!/bin/bash
while read -r line; do ## read each line of server.env
val="${line#*=}" ## trim to 1st =, save in val
export ${line%=$val}="$val" ## remove =$val leaving name, export val with name
done < server.env
printf "%s\n" "$PUBLIC_KEY" ## confirm
Example Use/Output
$ bash test.sh
ssh-rsa whatever+whatever+8whatever/whatever+p+whatever user#alans-MacBook-Pro.local
Where the basic Parameter Expansions are:
${var#pattern} Strip shortest match of pattern from front of $var
${var##pattern} Strip longest match of pattern from front of $var
${var%pattern} Strip shortest match of pattern from back of $var
${var%%pattern} Strip longest match of pattern from back of $var
(note: pattern can contain normal shell globs like '*' and '?')
There are literally dozens of useful parameter expansions you can use for string manipulations. Just check man bash under the "Parameter Expansion" heading.
PARTIAL ANSWER (does not export, so the variable is not available in subsequent runs of bash, only in the current session):
source server.env
The problem here is that field splitting still occurs on the whitespace.
You should do this:
export "$(cat server.env)"
(i.e. add double quotes).
For multiple variables, loop over the lines:
while read -r line
do
export "$line"
done < server.env
If this is in a script called export.sh, then you will also want to source it for the variables to be set in the current process:
source export.sh
This question already has answers here:
How do I split a string on a delimiter in Bash?
(37 answers)
Closed 4 years ago.
The post marked as duplicate above is similar, however is not sufficient for the use case. The below answers show a minimalist use of the read command to put parsed input for a known length of delimiter separated values into helpfully-named variables. For instance, if I read all four vars into $STATEMENTS,$BRANCHES,$FUNCTIONS,$LINES - a loop is not ideal as it adds a minimal of loop index awareness or 4 more lines to put each array var into a helpfully named var.
I have a list of comma separated numbers in a file:
26.16,6.89,23.82,26.17
I'd like to read these 4 numbers into helpfully named separate variable names - there will never fewer or more than 4 numbers.
Thanks for any help!
You'll need read builtin. The input stream, and variables to read can vary, based on your personal preferences. For instance,
IFS=,
LIST=1,2,3,4
read a b c d <<<$LIST
echo $a ; echo $b ; echo $c ; echo $d
This question already has answers here:
Difference between single and double quotes in Bash
(7 answers)
Closed 7 years ago.
I'm writing a bash script which contains a variable called "line", and I want to print it's content.
The problem is that the "line" variable is a string which contains the '$' char.
My question is how can I print the value of the "line" variable, without replacing the dollars with variables.
For example, if "line" is containing "a$#gz%^", this code:
echo $line
Will output this:
a0gz%^
And if I'll put the '$line' in single quotes, it will just print '$line':
echo '$line'
$line
Hope you'll be able to help.
You have to quote the string when you assign it to the variable:
line='a$#gz%^'
Otherwise, $# is expanded before the assignment.
To output the literal variable, use double quotes
echo "$line"
It looks confusing at first, but it is actually pretty simple (at least to a first approximation):
string with $line in it -- never what you want, particularly if it includes a variable. OK if there is no variable and the string is just letters and numbers (and pattern characters if you want them to be expanded). Expands variables, splits into words, expands filename patterns.
"string with $line in it" -- expands variables, but doesn't word split or expand filename patterns
'string with $line in it' -- literal string, just the characters between the apostrophes
You can store string in variable having special characters by giving escape sequence like below -
line="a\$#gz%^"
And then echo $line
This question already has answers here:
Read line by line in Bash script
(7 answers)
Closed 4 years ago.
I'm studying bash language and an exam track says this:
It should read one input (from standard input) at a time (each entry
is a string and then ends with a newline).
My questions are two:
How do I read line by line from standard input in Bash? Until now I used "read string" but I do not think that it reads a line at a time.
I do not know if this is a stupid question , but once created the script how can I give more lines to the script as input (read from standard input of course). For example from stdin I insert two lines (hello and world). How do I give to the bash script these two lines?
How do I read line by line from standard input in Bash? Until now I
used "read string" but I do not think that it reads a line at a time.
The prototype for read is:
read [options] name[s ...]
read will read a line of input into name name1 name2 ... splitting the line based on the contents of the Internal Field Separator (IFS). The default for IFS is ' \t\n' (that is space tab newline). If you only provide a single variable to read, you will read the entire line into that variable (unless you have set a new delimiter with the -d option to read). If you provide more than one variable, (e.g. read -r name name1) word splitting will occur based on the current value of IFS. Meaning if you provide the string hello world to:
read -r name
name="hello world". On the other hand, if you provide the same string to:
read -r name name1
name="hello", name1="world". What if you have excess words in the line but only 2 variables? Say your string is now "hello big wide world", what happens with:
read -r name name1
name="hello", name1="big wide world". The words in string are assigned to your variables in order and if there are insufficient variables to hold each word in the string, the last variable will contain all remaining words in the string not previously assigned.
You change how word splitting occurs by altering IFS. Take a close look at the answer provided by anubhava for an example. You are free to specify any character you would like the words to be split on. (helpful in say parsing a csv file to set IFS=$',\n' and have the words split on ',' instead of space)
To ensure you read an entire line into a variable, you can provide only a single variable to read and set IFS='$\n' to ensure word splitting only occurs on newline. (Note: providing the change as part of the while loop limits the IFS alteration to the scope of that loop. For example:
while IFS='$\n' read -r line; do
# do whatever with line
done
Will ensure that each line on stdin will be read into line while preserving normal word-splitting outside the loop. Inside the loop you can then add each line to an array as anubhava shows in his answer. (to preserve all whitespace IFS= is used)
You can do something like this:
# array to hold all lines read
lines=()
# read all lines in lines array
while IFS= read -r line; do
lines+=( "$line" )
done < file
# read 3 more lines from stdin
for ((i=0; i<3; i++)); do
read -rp "Enter a line: " line
lines+=( "$line" )
done
This question already has answers here:
Bash and filenames with spaces
(6 answers)
Closed 8 years ago.
I'm writing a script to do variable substitution into a Java properties file, of the format name=value. I have a source file, source.env like this:
TEST_ENV_1=test environment variable one
TEST_ENV_2=http://test.environment.com/one
#this is a comment with an equal sign=blah
TEST_ENV_3=/var/log/test/env/2.log
My script will replace every occurence of TEST_ENV_1 in the file dest.env with "test environment variable one", and so on.
I'm trying to process a line at a time, and having problems because looping on output from a command like sed or grep tokenizes on white space rather than the entire line:
$ for i in `sed '/^ *#/d;s/#.*//' source.env`; do
echo $i
done
TEST_ENV_1=test
environment
variable
one
TEST_ENV_2=http://test.environment.com/one
TEST_ENV_3=/var/log/test/env/2.log
How do I treat them as lines? What I want to be able to do is split each line apart on the "=" sign and make a sed script with a bunch of substitution regex's based on the source.env file.
sed '/^ *#/d;s/#.*//' source.env | while read LINE; do
echo "$LINE"
done
An alternative is to change $IFS as per #Jim's answer. It's better to avoid backticks in this case as they'll cause the entire file to be read in at once, whereas piping the output of sed to while above will allow the file to be processed line by line without reading the whole thing in to memory.