use external file with variables - bash

The following is iptable save file, which I modified by setting some variables like you see below.
-A OUTPUT -o $EXTIF -s $UNIVERSE -d $INTNET -j REJECT
I also have a bash script which is defining this variables and should call iptables-restore with the save file above.
#!/bin/sh
EXTIF="eth0"
INTIF="eth1"
INTIP="192.168.0.1/32"
EXTIP=$(/sbin/ip addr show dev "$EXTIF" | perl -lne 'if(/inet (\S+)/){print$1;last}');
UNIVERSE="0.0.0.0/0"
INTNET="192.168.0.1/24"
Now I need to use
/sbin/iptables-restore <the content of iptables save file>
in bash script and somehow insert the text file on top to this script, so the variables will be initialized. Is there any way to do that?
UPDATE: even tried this
/sbin/iptables-restore -v <<-EOF;
$(</etc/test.txt)
EOF

Something like this:
while read line; do eval "echo ${line}"; done < iptables.save.file | /sbin/iptables-restore -v
or more nicely formatted:
while read line
do eval "echo ${line}"
done < iptables.save.file | /sbin/iptables-restore -v
The eval of a string forces the variable expansion stuff.

Use . (dot) char to include one shell script to another:
#!/bin/sh
. /path/to/another/script

In your shell script:
. /path/to/variable-definitions
/sbin/iptables-restore < $(eval echo "$(</path/to/template-file)")
or possibly
/sbin/iptables-restore < <(eval echo "$(</path/to/template-file)")

Related

Bash: export .env variables [duplicate]

Let's say I have .env file contains lines like below:
USERNAME=ABC
PASSWORD=PASS
Unlike the normal ones have export prefix so I cannot source the file directly.
What's the easiest way to create a shell script that loads content from .env file and set them as environment variables?
If your lines are valid, trusted shell but for the export command
This requires appropriate shell quoting. It's thus appropriate if you would have a line like foo='bar baz', but not if that same line would be written foo=bar baz
set -a # automatically export all variables
source .env
set +a
If your lines are not valid shell
The below reads key/value pairs, and does not expect or honor shell quoting.
while IFS== read -r key value; do
printf -v "$key" %s "$value" && export "$key"
done <.env
This will export everything in .env:
export $(xargs <.env)
Edit: this requires the environment values to not have whitespace. If this does not match your use case you can use the solution provided by Charles
Edit2: I recommend adding a function to your profile for this in any case so that you don't have to remember the details of set -a or how xargs works.
This is what I use:
function load_dotenv(){
# https://stackoverflow.com/a/66118031/134904
source <(cat $1 | sed -e '/^#/d;/^\s*$/d' -e "s/'/'\\\''/g" -e "s/=\(.*\)/='\1'/g")
}
set -a
[ -f "test.env" ] && load_dotenv "test.env"
set +a
If you're using direnv, know that it already supports .env files out of the box :)
Add this to your .envrc:
[ -f "test.env" ] && dotenv "test.env"
Docs for direnv's stdlib: https://direnv.net/man/direnv-stdlib.1.html
Found this:
http://www.commandlinefu.com/commands/view/12020/export-key-value-pairs-list-as-environment-variables
while read line; do export $line; done < <(cat input)
UPDATE So I've got it working as below:
#!/bin/sh
while read line; do export $line; done < .env
use command below on ubuntu
$ export $(cat .env)

Bash pass date variable as string

I have a script which creates another script when run like this:
cat > "$installpath""tweets.sh" << ENDOFFILE
#!/bin/bash
source "$installpath"config.sh
cd \$webdir
/usr/local/bin/twint -s "\$search" --limit \$scrapelimit -o \$csvname --csv --database \$dbfile -ho
FILE=\$csvname
NAME=\${FILE%.*}
EXT=\${FILE#*.}
DATE=`\date +%d-%m-%Y-%H-%M`
NEWFILE=\${NAME}_\${DATE}.\${EXT}
echo \$NEWFILE
mv \$csvname \$NEWFILE
export NEWFILE
export DATE
ENDOFFILE
However, the script interprets the
DATE=`\date +%d-%m-%Y-%H-%M`
and changes it to
DATE=28-09-2019-15-49
I have tried escaping the variables in every possible way but nothing seems to work. Any ideas?
I suggest to use:
DATE=\$(date +%d-%m-%Y-%H-%M)

Bash: echo extract variables

Suppose there's a script called 'test.sh':
#!/bin/bash
while read line; do
APP=/apps echo "$line"
done < ./lines
And the 'lines':
cd $APP && pwd
If I bash test.sh, it prints out 'cd $APP && pwd'.
But when I type APP=/apps echo "cd $APP && pwd" in the terminal, it prints out 'cd /apps && pwd'.
Is it possible using echo to extract variables which are reading from a regular file?
Depending on the contents of the file, you may want to use eval:
#!/bin/bash
APP=/apps
while read line; do
eval "echo \"$line\"" # WARNING: dangerous
done < ./lines
However, eval is extremely dangerous. Although the quoting here will work for simple cases, it is quite easy to execute arbitrary commands by manipulating the input.
You should use eval to evaluate string line read from file
If you know the variable(s) you want to substitute, just substitute them.
sed 's%\$APP\>%/apps%g' ./lines

Bash command as variable

I am trying to store the start of a sed command inside a variable like this:
sedcmd="sed -i '' "
Later I then execute a command like so:
$sedcmd s/$orig_pkg/$package_name/g $f
And it doesn't work. Running the script with bash -x, I can see that it is being expanded like:
sed -i ''\'''\'''
What is the correct way to express this?
Define a shell function:
mysed () {
sed -i "" "$#"
}
and call it like this:
$ mysed s/$orig_pkg/$package_name/g $f
It works when the command is only one word long:
$ LS=ls
$ $LS
But in your case, the shell is trying the execute the program sed -i '', which does not exist.
The workaround is to use $SHELL -c:
$ $SHELL -c "$LS"
total 0
(Instead of $SHELL, you could also say bash, but that's not entirely reliable when there are multiple Bash installations, the shell isn't actually Bash, etc.)
However, in most cases, I'd actually use a shell function:
sedcmd () {
sed -i '' "$#"
}
Why not use an alias or a function? You can do alias as
alias sedcmd="sed -i '' "
Not exactly sure what you're trying to do, but my suggestion is:
sedcmd="sed -i "
$sedcmd s/$orig_pkg/$package_name/g $f
You must set variables orig_pkg package_name and f in your shell first.
If you're replacing variable names in a file, try:
$sedcmd s/\$orig_pkg/\$package_name/g $f
Still f must be set to the file name you're working on.
This is the right way for do that
alias sedcmd="sed -i ''"
Obviously remember that when you close your bash, this alias will be gone.
If you want to make it "permanent", you have to add it to your .bashrc home file (if you want to make this only for a single user) or .bashrc global file, if you want to make it available for all users

issue with creating file containing $ from bash script

I want produce udev rule file from bash script. For this I'm using cat command. Unfortunately produced file has missing "$" char. Here is example test.sh script:
#!/bin/sh
rc=`cat <<stmt1 > ./test.txt
-p $tempnode
archive/$env{ID_FS_LABEL_ENC}
stmt1`
Result is following:
cat test.txt
-p ''
archive/{ID_FS_LABEL_ENC}
Where issue is ?
If you don't want any variable interpolation, use:
#!/bin/sh
group="test_1"
cat <<'stmt1' > ./test.txt
-p $tempnode
archive/$env{ID_FS_LABEL_ENC}
stmt1
rc=$?
(Notice the '' around stmt1.)

Resources