Problem handling enviroment variable when launching terminal from bash script - bash

The following script gets called with an enviroment variable setted.
I need to launch a terminal and inside that terminal read that variable from another script ( script.sh ).
xfce4-terminal -x sh -c \
"export VAR='${VAR}'
/home/usr/scripts/script.sh"
It works but not when VAR has single quotes in it.
I also feel like there is a better way to pass enviroment variable to the terminal but I don't know how.
I really appreciate any kind of help and I'm sorry for my english.

One of the intended features of the environment is that you can add to it, but you never remove things from it. Add VAR to the current environment, and it will be inherited by xfce4-terminal and any process started by that terminal.
export VAR
xfce4-terminal -x sh -c /home/usr/scripts/script.sh
If you don't want it in the current environment, only in the new terminal's, then use a precommend assignment.
VAR="$VAR" xfce4-terminal -x sh -c /home/usr/scripts/script.sh
This avoids any fragile dynamic script construction like you are contending with.
Since xfce4-terminal appears to not fork a new process itself, I would pass the desired value as an argument to sh.
xfce4-terminal -x sh -c 'VAR="$1" /home/usr/scripts/script.sh' _ "$VAR"
The argument to -c is still a fixed string rather than one generated by interpolating the value of $VAR.

Related

how to execute docker sqlplus query inside bash script?

On Ubuntu 21.04, I installed oracle dtb from docker, works fine I am using it for sql developer but now I need to use it in shell script. I am not sure if it can work this way, or is it some better way. I am trying to run simple script:
#!/bin/bash
SSN_NUMBER="${HOME}/bin/TESTS/sql_log.txt"
select_ssn () {
sudo docker exec -it oracle bash -c "source /home/oracle/.bashrc; sqlplus username/password#ORCLCDB;" <<EOF > $SSN_NUMBER
select SSN from employee
where fname = 'James';
quit
EOF
}
select_ssn
After I run this, nothing happens and I need to kill the session. or
the input device is not a TTY
is displayed
Specifying a here document from outside Docker is problematic. Try inlining the query commands into the Bash command line instead. Remember that the string argument to bash -c can be arbitrarily complex.
docker exec -it oracle bash -c "
source /home/oracle/.bashrc
printf '%s\n' \\
\"select SSN from employee\" \\
\"where fname = \'James\'\;\" |
sqlplus -s username/password#ORCLCDB" > "$SSN_NUMBER"
I took out the sudo but perhaps you really do need it. I added the -s option to sqlplus based on a quick skim of the manual page.
The quoting here is complex and I'm not entirely sure it doesn't require additional tweaking. I went with double quotes around the shell script, which means some things inside those quotes will be processed by the invoking shell before being passed to the container.
In the worst case, if the query itself is static, storing it inside the image in a file when you build it will be the route which offers the least astonishment.

Bindsym does not execute i3wm command

This shortcut does not work in i3wm. It's supposed to show the window list of open apps.
Nothing visible happens, when keyboard shortcut is pressed.
bindsym $mod+space exec bash -c "/home/george/./dmenu-i3-window-jumper.sh"
However the script runs fine from terminal.
The bash code for the script:
https://github.com/minos-org/minos-desktop-tools/blob/master/tools/dmenu-i3-window-jumper
This is a two side issue
First some small config stuff:
I think you got an extra dot in there as ./ in that context just represents the folder preceding it (i.e: /home/george)
You can use the $HOME variable as a stand in for your home folder, i3 will pick it up
I would argue there is really no need for the bash -c, since your file has both a .sh extension and a #!/bin/sh header on the first line, which means you just need to give it execution permissions with chmod +x and it will run with bash anyways.
So in synthesis, you gotta
chmod +x /home/george/dmenu-i3-window-jumper.sh
so the script can be run without calling bash directly,
and your bindsym could be simplified to
bindsym $mod+space exec "$HOME/dmenu-i3-window-jumper.sh"
And then there is the script stuff:
You see, around line 44 the script checks to see if the STDIN is in a terminal, if its not then it tries to pipe a file to the arg array
if [ ! -t 0 ]; then
#add input comming from pipe or file to $#
set -- "${#}" $(cat)
fi
This seems to be the main problem, since you're not running the command in a terminal and you're not giving it a file either.
Your options are A: changing the if so it will always pass an empty string to the argument array
if [ ! -t 0 ]; then
#add input comming from pipe or file to $#
set -- "${#}" ""
fi
or B: create a dummy file with touch ~/dummy and then pass it to the script on the bindsym
bindsym $mod+space exec "$HOME/dmenu-i3-window-jumper.sh < $HOME/dummy"
Both seem to work fine on my setup, good luck!

How to create and set a system-wide environmental variable in Ubuntu through makefile?

I'm trying to create a system-wide environmental variable TEST_ENV_ONE.
I want to use it right after executing makefile without logout and after rebooting. So I'm trying to repeat manual moves like export variable and write it ti /etc/environment
I wrote a makefile like this, but it doesn't work:
var_value := some_string
TEST_ENV_ONE := $(var_value)
vars:
$(shell export TEST_ENV_ONE=$(var_value))
grep 'TEST_ENV_ONE=' /etc/environment || "TEST_ENV_ONE=\"$(var_value)\"" | sudo tee -a /etc/environment > /dev/null
What you want to do is basically impossible on a POSIX system as you've stated it. The environment of a process is inherited from its parent (the process that started it) and once a process is running, its environment cannot ever be changed externally. That includes by its children, or by modifying some other file.
You can, by modifying /etc/environment, change the environment for new logins but this will not change the environment of any existing shell or its child.
That being said, your makefile also has a number of problems:
$(shell export TEST_ENV_ONE=$(var_value))
This is doubly-not right. First, it's an anti-pattern to use the make $(shell ...) function inside a recipe script. Recipes are already shell scripts so it's useless (and can lead to unexpected behavior) to use $(shell ...) with them.
Second, this is a no-op: what this does is start a shell, tell the shell to set an environment variable and export it, then the shell exits. When the shell exits, all the changes to its environment are lost (obviously, because it exited!) So this does nothing.
Next:
grep 'TEST_ENV_ONE=' /etc/environment || "TEST_ENV_ONE=\"$(var_value)\"" | sudo tee -a /etc/environment > /dev/null
This does nothing because the statement "TEST_ENV_ONE=\"$(var_value)\"" sets an environment variable but generates no output, so there's no input to the sudo tee command and nothing happens. I expect you forgot an echo command here:
grep 'TEST_ENV_ONE=' /etc/environment || echo TEST_ENV_ONE=\"$(var_value)\" | sudo tee -a /etc/environment > /dev/null
However as I mention above, modifying /etc/environment will only take effect for new logins to the system, it won't modify any existing login or shell.

set env before bash initialization

I am creating new tab to run my command, and kill it when not needed.
$ roxterm --tab -e top
$ pkill -f top
(gnome-terminal is preferred, but doesn't support new tab to execute given command; splitting open & run fails to pkill).
My command requires a setup.sh script setting environment variables to be called prior to execution. However,
$ roxterm --tab -e "source setup.sh; mycommand"
fails, with the error line 1: source not found, as the bash environment is not yet initialized in the just being created roxterm env. How to circumvent.
One option i can think of is to create below script, myscript.sh
source setup.sh
mycommand
but i'd like to avoid creating scripts for each of my commands, and be able to kill it with pkill -f mycommand

Can /bin/bash -c export variable to parent shell

I'm trying to run arbitrary bash commands in the shell, but I can only access the shell buy running /bin/bash -c
Is there anyway of being able to run something like:
/bin/bash -c "export FOO=bar"
and then see FOO set in the original shell?
No.
This isn't shell-specific -- no UNIX process can change a parent process's environment variables without that parent process honoring an interface (for instance, reading new variables/values from stdout), or using unreliable and unsupportable hackery (like attaching to the parent process with a debugger and calling setenv() directly).
Consider ssh-agent as an example:
$ ssh-agent
SSH_AUTH_SOCK=/var/folders/t2/t58p1nwx1g38tkhykqfhvmm80000gn/T//ssh-0HSNi1V5h9wf/agent.17313; export SSH_AUTH_SOCK;
SSH_AGENT_PID=17314; export SSH_AGENT_PID;
echo Agent pid 17314;
...thus, documented for use with a pattern akin to:
$ eval "$(ssh-agent)"
In this case, that interface is eval-able shell code; however, as this is trivially used to execute arbitrary commands, supporting this interface is a security risk.
Inasmuch as your goal is to use the result of shell commands to modify the environment of a program that isn't a shell language at all, and thus doesn't support eval or source, this gives you the ability to use a safer stream format, such as a NUL-delimited stream. For instance, if your shell program writes key=val\0 pairs, with literal NUL characters for \0, you can do something akin to the following in Python:
for env_val in s.split('\0'):
if not env_val.contains('='): continue
k, v = env_val.split('=', 1)
environ[k] = v
...ported to your language of choice. To write in this format from shell:
printf '%s=%s\0' "$key" "$val"
...will suffice.

Resources