Environment Variables inside the container, but not used in the bash script - bash

I have an application that runs inside a docker container. First I build the image and then run the container. My run command is:
docker run --rm -it -e MODE=custom -e Station=RT -e StartDateReport=2022-09-10 -e Period=1 my-image:1.0.0
I declare the variables MODE, Station, StartDateReport and Period as environment variables. When I start a terminal from the container and type echo $MODE I will get the correct value, custom.
So far, so good, but I am interested in using these variables in a bash script. For example in start.sh I have the following code:
#!/bin/bash
if [[ $MODE == custom ]]; then
// do sth
fi
and here inside the script my variable MODE is undefined, and hence I obtain wrong results.
EDIT
As discussed in the comments below, my application if based on a cronjob to start running.
I managed to solve by myself the problem and the answer is in the comments.

In your environment, does your variable definition have the form
export MODE="custom"
Modified version of your script:
#!/bin/bash
test -z "${MODE}" && ( echo -e "\n\t MODE was not exported from calling environment.\n" ; exit 1 )
if [[ $MODE == custom ]]
then
#// do sth
echo "do sth"
fi

I found the solution for this problem, so I will post the answer here to help others that have the same problem. I found the solution here: How to load Docker environment variables in container
I included export xargs --null --max-args=1 echo < /proc/1/environ in start.sh
Thus, start.sh will be:
#!/bin/bash
export xargs --null --max-args=1 echo < /proc/1/environ
if [[ $MODE == custom ]]; then
// do sth
fi

Related

Rofi custom script on combi mode

I made a simple custom script to quick open a project on vscode thanks to ghq:
selection=$(ghq list | rofi -dmenu -p "Project" -no-custom)
[[ ! -z "${selection}" ]] && code ${HOME}/p/${selection}
exit 0
I bound it on i3 config:
bindsym $mod+d exec --no-startup-id rofi -show combi
bindsym $mod+p exec --no-startup-id ~/.config/rofi/project.sh
It works like a charm. Howeverm I want to make it part of the combi mode in order to have only one shortcut.
How can I achieve this?
If this is not possible with rofi, does a similar tool permit that?
It is possible to do by adding a script to your rofi config in ~/.config/rofi/config.rasi:
configuration {
combi-modi: "window,drun,ssh,Project:~/.config/rofi/project.sh";
modi: "combi";
}
Then you need to modify your script, so it will return a list of projects when no arguments are given and open a project when the script is launched with a project name as an argument:
#!/usr/bin/env sh
# List projects if no arguments given
if [ -z "$1" ]; then
ghq list
else
code "$HOME/p/$1"
fi
Now, rofi -show combi should open with a default combi mode+project launcher.
By the way, I am not sure if the exit 0 at the end of the script is needed. It makes the script always return successful status, no matter the exit status of used commands. See the answer here.
In my case, I was trying a simple file finder script for rofi
At first my attempt was:
fd -H . ~ | rofi -dmenu | xargs xdg-open > /dev/null 2>&1 &
Calling the script from the command line works like a charm, but when I tried this inside rofi, didn't work. Of course I can't call rofi indide rofi
Following the idea here, given by Cezary,I got to this:
#!/bin/bash
if [[ -z "$1" ]]; then
fd -H . ~
else
xdg-open "$1" > /dev/null 2>&1 &
fi
Turns out, de > /dev/null 2>&1 & was important, so it wouldn't freeze the whole thing. Maybe only the "&" in the end is important, so the process goes to the background? The rest, as I understand, just throws away any output or errors.
In my "config.rasi" from rofi, I have the line
modi: "drun,Finder:/path/to/script";
since I want it as a second mode, instead of a combi. Of course I made it executable with chmod +x.

How can a Bash command remember and toggle a setting?

I want to have a launcher that runs a Bash commands that toggle a setting; switching the setting one way requires one command and switching it the other way requires another command. If there is no easy way to query the system to find out the status of that setting, how should Bash remember the status of the setting so that it can run the appropriate command?
An obvious solution would be to save the status as files and then check for the existence of those files to determine the appropriate command to run, but is there some neater way, perhaps one that would use volatile memory?
Here's an attempt at a toggle script using temporary files:
#!/bin/bash
main(){
settingOn="/tmp/red_on.txt"
settingOff="/tmp/red_off.txt"
if [[ ! -e "${settingOff}" ]] && [[ ! -e "${settingOn}" ]]; then
echo "no prior use detected -- creating default off"
touch "${settingOff}"
fi
if [ -f "${settingOff}" ]; then
echo "switch on"
redshift -o -t 1000:1000 -l 0.0:0.0
rm -f "${settingOff}"
touch "${settingOn}"
elif [ -f "${settingOn}" ]; then
echo "switch off"
redshift -x
rm -f "${settingOn}"
touch "${settingOff}"
fi
}
main

How to escape space in bash script from inline if?

I know that similar questions have been asked and answered before on stackoverflow (for example here and here) but so far I haven't been able to figure it out for my particular case.
I'm trying to create a script that adds the -v flag only if the variable something is equal to "true" (what I'm trying to do is to mount the current folder as a volume located at /src in the Docker container):
docker run --name image-name `if [ "${something}" == "true" ]; then echo "-v $PWD:/src"; fi` ....
The problem is that $PWD may contain spaces and if so my script won't work. I've also tried assigning "$PWD" to an intermediate variable but it still doesn't work:
temp="$PWD"
docker run --name image-name `if [ "${something}" == "true" ]; then echo "-v $temp:/src"; fi` ....
If I run:
docker run --name image-name -v "$PWD":/src ....
from plain bash (without using my script) then everything works.
Does anyone know how to solve this?
Use an array.
docker_args=()
if something; then
docker_args+=( -v "$PWD/src" )
fi
docker run --blah "${docker_args[#]}" …
Don't have arrays? Use set (in a function, so it doesn't affect outer scope).
Generally:
knacker() {
if something; then
set -- -v "$PWD:/src" "$#"
fi
crocker "$#"
}
knacker run --blah
But some commands (like docker, git, etc) need special treatment because of their two-part command structure.
slacker() {
local cmd="$1"
shift
if something; then
set -- -v "$PWD:/src" "$#"
fi
docker "$cmd" "$#"
}
slacker run --blah
Try this (using the array way):
declare -a cmd=()
cmd+=(docker run --name image-name)
if [ "${something}" = "true" ]
then
cmd+=(-v "$PWD:/src")
fi
"${cmd[#]}"

bash programming - best practice setting up variables within a loop or not

I have the following logic in my bash/shell script. Where essentially, I'm trying to pass one argument manually and then passing in other values from a hidden file, like so:
if [[ $# != 1 ]]; then
echo "./tstscript.sh <IDNUM>" 2>&1
exit 1
fi
MYKEY=/dev/scripts/.mykey
if [ -f "$MYKEY" ]
then
IFS=';'
declare -a arr=($(< $MYKEY))
# DECLARE VARIABLES
HOSTNM=localhost
PORT=5432
PSQL_HOME=/bin
IDNUM=$1
DBU1=${arr[0]}
export HOSTNM PORT PSQL_HOME IDNUM DBU1 DBU2
$PSQL_HOME/psql -h $HOSTNM -p $PORT -U $DBU1 -v v1=$IDNUM -f t1.sql postgres
else
echo "Mykey not found"
fi
rt_code=?
exit 1
Am I declaring my variables in the right place? Should it be declaring within my if statement?
Most of your variables are redundant. psql already has a few well-known environment variables it will use if you don't specify various parameters on the command line. The others are just hard-coded, so it's not really important to define them. It really doesn't matter much where you define them, as long as you define them before they are used, since this isn't a very large script. It's a good sign that you've outgrown shell script and are ready for a more robust programming language when you start worrying about the design of the shell script.
if [[ $# != 1 ]]; then
echo "./tstscript.sh <IDNUM>" 2>&1
exit 1
fi
MYKEY=/dev/scripts/.mykey
if ! [ -f "$MYKEY" ]; then
echo "Mykey not found"
exit 1
fi
# You only use the first word/line of the file,
# so this should be sufficient.
IFS=";" read -a arr < "$MYKEY"
export PGHOST=localhost
export PGPORT=5432
export PGUSER=${arr[0]}
: ${PSQL_HOME:=/bin}
"$PSQL_HOME"/psql -v v1="$1" -f t1.sql postgres
When you fill /dev/scripts/.mykey with lines in the form key=value, you can source that file.
$ cat /dev/scripts/.mykey
DBU1=noober
FIELD2="String with space"
echo "Keep it clean, do not use commands like this echo in the file"
In your script you can activate the settings by sourcing the file
if [ -f "${MYKEY}" ]; then
. "${MYKEY}"
# Continue without an array, DBU1 and FIELD2 are set.

Create shell sub commands by hierarchy

I'm trying to create a system for my scripts -
Each script will be located in a folder, which is the command itself.
The script itself will act as a sub-command.
For example, a script called "who" inside a directory called "git",
will allow me to run the script using git who in the command line.
Also, I would like to create a sub command to a psuedo-command, meaning a command not currently available. E.g. some-arbitrary-command sub-command.
Is that somehow possible?
I thought of somehow extending https://github.com/basecamp/sub to accomplish the task.
EDIT 1
#!/usr/bin/env bash
command=`basename $0`
subcommand="$1"
case "$subcommand" in
"" | "-h" | "--help" )
echo "$command: Some description here" >&2
;;
* )
subcommand_path="$(command -v "$command-$subcommand" || true)"
if [[ -x "$subcommand_path" ]]; then
shift
exec "$subcommand_path" "${#}"
return $?
else
echo "$command: no such command \`$subcommand'" >&2
exit 1
fi
;;
esac
This is currently the script I run for new custom-made commands.
Since it's so generic, I just copy-paste it.
I still wonder though -
can it be generic enough to just recognize the folder name and create the script by its folder name?
One issue though is that it doesn't seem to override the default command name, if it supposed to replace it (E.g. git).
EDIT 2
After tinkering around a bit this is what I came to eventuall:
#!/usr/bin/env bash
COMMAND=`basename $0`
SUBCOMMAND="$1"
COMMAND_DIR="$HOME/.zsh/scripts/$COMMAND"
case "$SUBCOMMAND" in
"" | "-h" | "--help" )
cat "$COMMAND_DIR/help.txt" 2>/dev/null ||
command $COMMAND "${#}"
;;
* )
SUBCOMMAND_path="$(command -v "$COMMAND-$SUBCOMMAND" || true)"
if [[ -x "$SUBCOMMAND_path" ]]; then
shift
exec "$SUBCOMMAND_path" "${#}"
else
command $COMMAND "${#}"
fi
;;
esac
This is a generic script called "helper-sub" I symlink to all the script directories I have (E.g. ln -s $HOME/bin/helper-sub $HOME/bin/ssh).
in my zshrc I created this to call all the scripts:
#!/usr/bin/env bash
PATH=${PATH}:$(find $HOME/.zsh/scripts -type d | tr '\n' ':' | sed 's/:$//')
export PATH
typeset -U path
for aliasPath in `find $HOME/.zsh/scripts -type d`; do
aliasName=`echo $aliasPath | awk -F/ '{print $NF}'`
alias ${aliasName}=${aliasPath}/${aliasName}
done
unset aliasPath
Examples can be seen here: https://github.com/iwfmp/zsh/tree/master/scripts
You can't make a directory executable as a script, but you can create a wrapper that calls the scripts in the directory.
You can do this either with a function (in your profile script or a file in your FPATH) or with a wrapper script.
A simple function might look like:
git() {
local subPath='/path/to/your/git'
local sub="${1}" ; shift
if [[ -x "${subPath}/${1}" ]]; then
"${subPath}/${sub}" "${#}"
return $?
else
printf '%s\n' "git: Unknown sub-command '${sub}'." >&2
return 1
fi
}
(This is the same way that the sub project you linked works, just simplified.)
Of course, if you actually want to create a sub-command for git specifically (and that wasn't just an example), you'll need to make sure that the built-in git commands still work. In that case you could do like this:
git() {
local subPath='/path/to/your/git'
local sub="${1}"
if [[ -x "${subPath}/${sub}" ]]; then
shift
"${subPath}/${sub}" "${#}"
return $?
else
command git "${#}"
return 1
fi
}
But it might be worth pointing out in that case that git supports adding arbitrary aliases via git config:
git config --global alias.who '!/path/to/your/git/who'

Resources