source env variables files inside Makefile - linux

so from my local machine I am able to do this:
. env_vars.env
and it works fine:
cat env_vars.env
#!/bin/bash
export abce=def
but when I try to reflect same in makefile it returns nothing:
SHELL=/bin/bash
print-env-vars:
. env_vars.env
echo ${abce}
I also tried with source env_vars.env inside makefile but output is still the same. Wondering how can I source variables inside the makefile.

Each line of a make recipe is executed by a separate shell, so even if you source the file, the shell that sources it exits before the next line is evaluated. It's equivalent to running the following from your shell:
bash -c '. env_vars.env'
bash -c 'echo ${abce}'
Put both commands on the same line (or use \ to split a single logical line across multiple physical lines) so that both are executed in the same shell. The semicolon is necessary so that the shell doesn't see . env_vars.env echo ${abce}
as the single command to run.
print-env-vars:
. env_vars.env; \
echo $${abce}
(The double dollar sign ensures that you actually pass a parameter expansion to the shell, rather than make trying to expand a make variable.)

Related

how can we change the directory in linux using perl script after taking input from user [duplicate]

How to set a global environment variable in a bash script?
If I do stuff like
#!/bin/bash
FOO=bar
...or
#!/bin/bash
export FOO=bar
...the vars seem to stay in the local context, whereas I'd like to keep using them after the script has finished executing.
Run your script with .
. myscript.sh
This will run the script in the current shell environment.
export governs which variables will be available to new processes, so if you say
FOO=1
export BAR=2
./runScript.sh
then $BAR will be available in the environment of runScript.sh, but $FOO will not.
When you run a shell script, it's done in a sub-shell so it cannot affect the parent shell's environment. You want to source the script by doing:
. ./setfoo.sh
This executes it in the context of the current shell, not as a sub shell.
From the bash man page:
. filename [arguments]
source filename [arguments]
Read and execute commands from filename in the current shell
environment and return the exit status of the last command executed
from filename.
If filename does not contain a slash, file names in PATH are used to
find the directory containing filename.
The file searched for in PATH need not be executable. When bash is not
in POSIX mode, the current directory is searched if no file is found
in PATH.
If the sourcepath option to the shopt builtin command is turned off,
the PATH is not searched.
If any arguments are supplied, they become the positional parameters
when filename is executed.
Otherwise the positional parameters are unchanged. The return status
is the status of the last command exited within the script (0 if no
commands are executed), and false if filename is not found or cannot
be read.
source myscript.sh is also feasible.
Description for linux command source:
source is a Unix command that evaluates the file following the command,
as a list of commands, executed in the current context
#!/bin/bash
export FOO=bar
or
#!/bin/bash
FOO=bar
export FOO
man export:
The shell shall give the export attribute to the variables corresponding to the specified names, which shall cause them to be in the environment of subsequently executed commands. If the name of a variable is followed by = word, then the value of that variable shall be set to word.
A common design is to have your script output a result, and require the cooperation of the caller. Then you can say, for example,
eval "$(yourscript)"
or perhaps less dangerously
cd "$(yourscript)"
This extends to tools in other languages besides shell script.
In your shell script, write the variables to another file like below and source these files in your ~/.bashrc or ~/.zshrc
echo "export FOO=bar" >> environment.sh
In your ~/.bashrc or ~/.zshrc, source it like below:
source Path-to-file/environment.sh
You can then access it globally.
FOO=bar
export FOO

Why do quotes in shell scripts behave differently from quotes in shell commands?

I'm using WSL (Ubuntu 18.04) on Windows 10 and bash.
I have a file filename.gpg with the content:
export SOME_ENV_VAR='123'
Now I run the following commands:
$ $(gpg -d filename.gpg)
$ echo $SOME_ENV_VAR
'123' <-- with quotes
However, if I run it directly in the shell:
$ export SOME_ENV_VAR='123'
$ echo $SOME_ENV_VAR
123 < -- without quotes
Why does it behave like this? Why is there a difference between running a command using $() and running it directly?
Aside: I got it working using eval $(gpg -d filename), I have no idea why this works.
Quotes in shell scripts do not behave differently from quotes in shell commands.
With the $(gpg -d filename.gpg) syntax, you are not executing a shell script, but a regular single command.
What your command does
It executes gpg -d filename.gpg
From the result, it takes the first (IFS-separated) word as the command to execute
It takes every other (IFS-separated) words, including words from additional lines, as its parameters
It executs the command
From the following practical examples, you can see how it differs from executing a shell script:
Remove the word export from filename.gpg: the command is then SOME_ENV_VAR='123' which is not understood as a variable assignment (you will get SOME_ENV_VAR='123': command not found).
If you add several lines, they won't be understood as separated command lines, but as parameters to the very first command (export).
If you change export SOME_ENV_VAR='123' to export SOME_ENV_VAR=$PWD, SOME_ENV_VAR will not contain the content of variable PWD, but the string $var
Why is it so?
See how bash performs expansion when analyzing a command.
There are many steps. $(...) is called "command substitution" and is the fourth step. When it is done, none of the previous steps will be performed again. This explains why your command does not work when you remove the export word, and why variables are not substituted in the result.
Moreover "quote Removal" is the last step and the manual reads:
all unquoted occurrences of the characters ‘\’, ‘'’, and ‘"’ that did
not result from one of the above expansions are removed
Since the single quotes resulted from the "command substitution" expansion, they were not removed. That's why the content of SOME_ENV_VAR is '123' and not 123.
Why does eval work?
Because eval triggers another complete parsing of its parameters. The whole set of expansions is run again.
From the manual:
The arguments are concatenated together into a single command, which is then read and executed
Note that this means that you are still running one single command, and not a shell script. If your filename.gpg script has several lines, subsequent lines will be added to the argument list of the first (and only) command.
What should I do then?
Just use source along with process substitution.
source <(gpg -d filename.gpg)
Contrary to eval, source is used to execute a shell script in the current context. Process substitution provides a pseudo-filename that contains the result of the substitution (i.e. the output of gpg).

How to call a variable in a bash command line?

I am trying to create this little program to help me, with only one command, to compile and run a C program within Ubuntu's terminal.
Trying to make it fancier, I added an argument to the bash file so I can use it for any C program I want. So this is how it is supposed to go:
Create a variable to store the name of the file
Use that variable to compile the program (to the same file name)
Use that same name to run the file.
Here is the code:
# usr/bin/bash
filename=$1
cc -o $filename "$filename.c"
./$filename.out
almost everything runs, the only problem I still have is in the last line:
./$filename.out
It doesn't seem to use the name of the variable inside the command which executes the final program.
I'm a noob at bash (let's say I haven't used it in months).
cc -o foo will output foo not foo.out. You should also double-quote the variable expansions to prevent IFS-splitting and globbing:
filename=$1
cc -o "$filename" "$filename.c" &&
./"$filename"
Apart from that # /usr/bin/bash (unlike #!/usr/bin/bash) does nothing. It's a comment. The whole thing will be run the /bin/sh, not bash (but you don't need bash, anyway).
You will need to use quotation marks:
./"$filename.out"
#!/bin/sh
filename=$1
cc -o "${filename}.out" "${filename}.c"
"./${filename}.out"

why does "source ~/.profile" keep adding to my $PATH?

This is not a problem affecting me in any way, but just for curiosity...
I have added export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
to my ~/.profile to include a new directory into my bash search.
Then, I ran $ source ~/.profile to reload may shell and I checked my path using $ echo $PATH
The question is:
- why every time I ran source ~/.profile, it appends the same information again,
- how can I clear it?
What I have tried:
- Tried running it multiple times and it keeps adding the same
- Tried to figure out what does the source command does but could not find where it is which source
First question:
why every time I ran source ~/.profile, it appends the same
information again
Simply, source <FILE> does not reload your shell. It only
executes all commands saved in <FILE> as if they were typed directly
by you in the terminal.
Second question:
how can I clear it?
To reload shell open a new terminal
window/tab. Doing just bash or exec bash won't work because a new
process will inherit its parent environment.
Third question:
Tried to figure out what does the source command does but could not
find where it is which source
As I explained once here https://unix.stackexchange.com/a/202326/72304:
All commands that can be run in Bash without typing an explicit path
to it such as ./command can be divided into two parts: Bash shell
builtins and external commands. Bash shell builtins come installed
with Bash and are part of it while external commands are not part of
Bash. This is important because Bash shell builtins are documented
inside man bash and their documentation can be also invoked with help
command while external commands are usually documented in their own
manpages or take some king of -h, --help flag. To check whether a
command is a Bash shell builtin or an external command:
$ type local
local is a shell builtin
It will display how command would be interpreted if used as a command
name (from help type). Here we can see that local is a shell builtin.
Let's see another example:
$ type vim
vim is /usr/bin/vim
In your case:
$ type source
source is a shell builtin
Now we know it's not an external command but a shell bultin (this is why which does not find it) so we need to use help to see what it does:
$ help source
source: source filename [arguments]
Execute commands from a file in the current shell.
Read and execute commands from FILENAME in the current shell. The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.
Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.
source executes the content of the file passed as argument in the current shell.
It appends the same information again because export is appending a string to PATH, without checking anything (it is not checking if the substring that you want to append is already in the variable).
To avoid appending to PATH every time, you should save the values of your PATH without referring to itself, e.g.:
export PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/local/go/bin:$GOPATH/bin
Edit:
To check if the directory is already in PATH:
if [[ ":$PATH:" != *":/usr/local/go/bin:$GOPATH/bin:"* ]]; then
export PATH=$PATH:/usr/local/go/bin:$GOPATH/bin
fi

xdg .desktop file shell expansion

I'm trying to figure out if it's possible to create a something.desktop file in ~/.local/share/applications that successfully executes the command chromium --user-data-dir=$(mktemp -d) every time
The relevant line in the .desktop file is the Exec entry in the following example:
$ cat ~/.local/share/applications/something.desktop
[Desktop Entry]
Name=chromecognito
Exec=chromium --user-data-dir\=\$\(mktemp -d\)
Icon=chromecognito
Type=Application
Categories=GTK;GNOME;Utility;
I've seen this question, which references this document and tried various combinations of escapes of $, (, ), =, ", etc. in the Exec line, as well as working with single quotes, but haven't been able to get it to use a new temp directory every time the program is started from the "start menu"
As a side note, using the line Exec=/home/myuser/bin/chromecognito where /home/myuser/bin/chromecognito looks like this:
$ cat /home/myuser/bin/chromecognito
#! /usr/bin/env bash
(chromium --user-data-dir=$(mktemp -d) &)
works, although I haven't even successfully been able to use a tilde like ~/bin/chromecognito for the Exec entry in the .desktop file. Maybe that's is a good starting point.
Exec=sh -c "chromium --user-data-dir=$(mktemp -d)"
Please note that both $(cmd) and ~ would be interpreted by the shell, so you must call a shell first to make those symbols work.

Resources