Neil C. Obremski
Neil C. Obremski

Reputation: 20344

How to print env var from file in bash (without using source)?

Many shell scripts, including the bash profile, are simply lists of environment variable settings. One such script on Debian is /etc/os-release which looks like this:

PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

The VERSION_CODENAME is particularly useful for adding to apt sources (/etc/apt/sources.list) for, say, Steam to work on ChromeOS. Note that most instructions hard-code this value which can cause compatibility problems.

So my question then is how to echo an env var such as VERSION_CODENAME from a file such as /etc/os-release without using source? That's key because I don't want to clutter up my environment variables with these for a one-time use.

Here's what I know I can do now but it leaves the variables in my current environment which is undesirable:

source /etc/os-release && echo "deb http://httpredir.debian.org/debian/ $VERSION_CODENAME main contrib non-free | sudo tee -a /etc/apt/sources.list"

I thought perhaps there is a way to start a new (temporary) bash process and load the variables into that environment. I haven't been able to figure that out without an actual shell script.

Upvotes: 1

Views: 4142

Answers (4)

F. Hauri  - Give Up GitHub
F. Hauri - Give Up GitHub

Reputation: 71087

4 different answer here...

Sorry, but there is more than one way;). You may found a lot of other ways, but there are the most appropriate (quickness, efficience, footprint, readability...).

1. import through sed to populate associative arrray:

declare -A IMPORTED="($(sed < /etc/os-release 's/^\([^=]\+\)=/[\1]=/'))"

Then

echo ${IMPORTED[VERSION_CODENAME]}
buster

2. extract required field (by using sed again)

AltVersionCodename=$(sed </etc/os-release -ne 's/^VERSION_CODENAME=//p')
echo $AltVersionCodename
buster

3. parenthesis to drop down to subshell using his own environment

( . /etc/os-release ; echo $VERSION_CODENAME )
buster

echo $VERSION_CODENAME
 

Current environment don't know about $VERSION_CODENAME

4. reading variable file in pure bash, without forks

As we are working on a small file, we could use loop to read the file until required info is found:

while IFS== read varname value;do
    [ "$varname" = "VERSION_CODENAME" ] &&
        ImportedVersionCodename=$value && break
done </etc/os-release
echo $ImportedVersionCodename 
buster

Upvotes: 2

Walter A
Walter A

Reputation: 20032

The next function only sources the line with the key (value in single quotes).

my_set() {
   configfile="$1"
   key="$2"
   print -v "$key" $(sed -n "s/^${key}=//p" "${configfile}")
}
my_set /etc/os-release VERSION_CODENAME
echo "deb http://httpredir.debian.org/debian/ $VERSION_CODENAME main.."

When you don't need the var in the environment, use

my_set2() {
   configfile="$1"
   key="$2"
   sed -n "s/^${key}=//p" "${configfile}"
}

echo "deb http://httpredir.debian.org/debian/ $(my_set2 /etc/os-release VERSION_CODENAME) main.."

Upvotes: 1

Ivan
Ivan

Reputation: 7327

Or using read and printf like this:

while read line; do
    name=${line%%=*}
    data=${line#*=}
    printf -v $name "${data//\"}"
done < vars

Upvotes: 1

Charles Duffy
Charles Duffy

Reputation: 296049

I thought perhaps there is a way to start a new (temporary) bash process and load the variables into that environment.

That's what using parenthesis to create a subshell does.

(
  . /etc/os-release
  echo "deb http://httpredir.debian.org/debian/ $VERSION_CODENAME main contrib non-free" \
  | sudo tee -a /etc/apt/sources.list
)

...as soon as the ) is hit, your variables are removed, as the subshell they were loaded into exits.

Upvotes: 1

Related Questions