Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash: defining a file-local variable invisible to sourcing script

Tags:

bash

Say I have a bash script file config.sh. It's meant to be source'd by other scripts and variables defined is used as customization of the upper-level scripts.

The problem is, if config.sh has a temporary variable and its name conflicts with upper-level scripts' variable, it breaks the upper-level one.

config.sh:

TMP1=abc CONFIG_INPUT_DIR="$TMP1"/in CONFIG_OUTPUT_DIR="$TMP1"/out 

upper-level script:

TMP1=def source config.sh echo $TMP1 

The last echo prints abc, not def.

Solution 1

My current solution is to append a random string to the temporary variable name to make it almost impossible to conflict. e.g:

TMP1_vFc9Uiew=abc CONFIG_INPUT_DIR="$TMP1_vFc9Uiew"/in CONFIG_OUTPUT_DIR="$TMP1_vFc9Uiew"/out unset TMP1_vFc9Uiew 

which is painful and makes the code hard to read, in addition not to be perfect.

Solution 2 using local keyword

After some searching, I've come to know local keyword. But when I simply declare TMP1 as local, bash complains that config.sh: line 1: local: can only be used in a function.

So my another solution is to enclose whole config script as a function:

function config_func_rZ0Yqkpm() {   local TMP1=abc   CONFIG_INPUT_DIR="$TMP1"/in   CONFIG_OUTPUT_DIR="$TMP1"/out } config_func_rZ0Yqkpm unset config_func_rZ0Yqkpm 

which is better than previous solution in maintainability and readability, but there's some possibility to conflict as well as solution 1.

Question

I want to know more robust and smart solution without any possibility to conflict.

Thanks.

like image 646
niboshi Avatar asked Feb 09 '12 03:02

niboshi


People also ask

How do you set local variables in bash?

The easiest way to set environment variables in Bash is to use the “export” keyword followed by the variable name, an equal sign and the value to be assigned to the environment variable.

What is $@ in bash script?

bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.

What does ${ 1 mean in bash script?

- 1 means the first parameter passed to the function ( $1 or ${1} ) - # means the index of $1 , which, since $1 is an associative array, makes # the keys of $1. - * means the values of of the # keys in associate array $1.

Are bash variables scoped?

Variable Scope of Bash FunctionsBy default, every variable has a global scope that means it is visible everywhere in the script. You can also create a variable as a local variable. When you declare a local variable within the function body, it is only visible within that function.


2 Answers

A trick I learned from the keychain utility is using one program to build a source-able file containing just the variables that you want to export from your program. You could modify your script to echo the variables you want to set and then source the output from your program:

$ echo $FOO  $ source <(echo FOO=bar) $ echo $FOO bar $  

I used echo FOO=bar to simulate the larger script; your program is probably more involved. The important part is that you must modify your program to output the variables and values you would like to set, rather than just setting them. This lets you decide which variables to expose and which ones to hold private at the cost of another shell process.

like image 63
sarnold Avatar answered Oct 08 '22 07:10

sarnold


You could avoid variables and use functions in config.sh to hold your values:

get_dirname() { echo "abc"; } CONFIG_INPUT_DIR="$(get_dirname)/in" CONFIG_OUTPUT_DIR="$(get_dirname)/out" unset -f get_dirname 

If you're still concerned about name collision for functions, this doesn't really help you.

like image 44
glenn jackman Avatar answered Oct 08 '22 06:10

glenn jackman