Shell command to get config values - shell

I am using the sh 3.2 in Mac Os X. I have a file test.conf
config1="Configuration 1"
config2="a lot of text"
config3=...
So I only need to get the config1= and config2= parameter. How can I set a variable, that I can do this:
> echo $variable
Configuration 1
So simple, but I am not doing it work.

the sommand you are looking for is source
source test.conf
echo $config1 #echoes Configuration 1
if you need to have config1 in variable, add
varible=$config1

At a rough guess...
export `grep 'config1=' /your/config/file`
export `grep 'config2=' /your/config/file`
But remember if you put this in a shell script file, then you'll need to eval the file rather than execute it to set the variables in the current shell instance.

You could do this:
variable=`sed -n 's/^config1=//p'`
Or if you are attempting to evaluate certain parts of your file, try something like
eval `grep ^config1= test.conf`
to have config1=Configuration 1 evaluated by the current shell. (With the example you provided, this will cause a syntax error, because the value cannot contain unquoted whitespace.)
I generally recommend beginners to stay away from backticks, but this is a situation where they are a good answer.

Related

Why bash script does not run well?

I write a code in Bash script and the Linux does not run it correctly and printed character instead of character’s value.
Can anyone help me?
Aside from the confusion between backtick and ', you are also over-using the sub-shell syntax. You do not need to use echo $(cat $LOOP). You can just run cat $LOOP directly.
#!/bin/bash
for FILE in $(ls); do
echo "Here is ${file}:"
cat ${FILE}
echo ""
done
A couple of points of style as well:
Name your variables after the thing they represent. The loop is iterating over files in the current directory, so the name FILE is more descriptive than LOOP.
It is a good idea to get in the habit of enclosing your variable references in ${ ... } instead of just prefixing them with $. In simple scripts like this, it does not make a difference, but when your scripts get more complicated, you can get into trouble when you do not clearly delineate variable names.

Use content of file as part of a Bash command

I want to use the content of a file.txt as part of a bash command.
Suppose that the bash command with its options that I want to execute is:
my_command -a first value --b_long_version_option="second value" -c third_value
but the first 2 options (-a and --b_long_version_option ) are very verbose so instead of inserting directly on the command line (or bash script) I wrote them in a file.txt like this:
-a first value \
--b_long_version_option="second value"
Now I expect to call the command "my_command" with the following syntax (where "path_to/file.txt" is the path to file.txt, expressed in relative or absolute form):
my_command "$(cat path_to/file.txt)" -c third_value
This however is not the right syntax, as my command is breaking and complaining.
How should I write the new version of the command and/or the file.txt so that it is equivalent to its native bash usage?
Thanks in advance!
The quotes are preserving the newlines. Take them off.
You also don't need the cat unless you're running an old bash parser.
my_command $(<path_to/file.txt) -c third_value
You'll need to take the backslashes at the ends of lines out.
Be careful doing things like this, though. It's probably better to just put the whole command in the file, rather than just pieces of it. If you really just want arguments, maybe define them a little more carefully in an array, source the file and then apply them, like this:
in file:
myArgs=( "-a" "first value"
"--b_long_version_option=second value"
)
Note the quoting. Then run with
. file
my_command "${myArgs[#]" -c third_value
e.g.,
$: printf "[%s] " "${myArgs[#]}" -c=foo
[-a] [first value] [--b_long_version_option=second value] [-c=foo]
I haven't seen any example of what you're trying. But, there are simpler ways to achieve your goal.
Bash Alias
ll for example is a bash alias for ls -al. It usually is defined in .bash_profile or .bashrc as follows :
alias ll='ls -al'
So, what you can do is to set another alias for your shorthand command.
alias mycmd='mycommand -a first value --b_long_version_option="second value"'
then you can use it as follows :
mycmd -c third_value
Config file
You can also define a mycommand.json file or mycommand.ini file for default arguments. Then, you will need to check for config file in your software, and assign arguments from it.
Using config file is more advanced solution. You can define multiple config files. You can set default config file in /etc/mycommand/config.ini for example. When running on different directories, you should check ${cwd}/mycommand.ini to check local config file exists or not. You can even add a --config-file argument to your command.
Using alias is more convenient for small tasks, or thing that won't change much. If your command's behavior should be different in some other project, the using a config file would be a better solution.

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

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.
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.
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.
The "ssh-agent" method:
config.sh
#!/bin/bash
TMP=abc
printf "CONFIG_INPUT_DIR=%s/in\n" "$TMP"
printf "CONFIG_OUTPUT_DIR=%s/out\n" "$TMP"
main program:
TMP1=def
eval "$(config.sh)"
echo "$TMP1"

Problem in running a script

i have unix shell script which is need to be run like below
test_sh XYZ=KLMN
the content of the script is
#!/bin/ksh
echo $XYZ
for using the value of XYZ i have do set -k before i run the script.
is there a way where i can do this without doint set -k before running the script. or is there something that i can do in the script where i can use value of the parameter given while running the script in the below way
test_sh XYZ=KLMN
i am using ksh.
Any help is appreciated.
How about running this?
XYZ=KLMN ./test_sh //running from directory where test_sh is
If your script needs no other arguments, a quick and dirty way do to it is to put
eval "$#"
at the start of your script. This will evaluate the command line arguments as shell commands. If those commands are to assign a shell/environment variable, then that's what it will do.
It's quick-and-dirty since anything could be put on the command line, causing problems from a syntax error to a bad security hole (if the script is trusted).
I'm not sure if "$#" means the same in ksh as it does in bash - using just $* (without quotes) would work too, but is even dirtier.
It looks like you are trying to use the environment variable "INSTANCE" in your script.
For that, the environment variable must be set in advance of executing your script. Using the "set" command sets exportable environment variables. Incidentally, my version of ksh dates from 1993 and the "-k" option was obsolete back then.
To set an environment variable so that it is exported into spawned shells, simply use the "export" command like so:
export INSTANCE='whatever you want to put here'
If you want to use a positional parameter for your script -- that is have the "KLMN" value accessed within your script, and assuming it is the first parameter, then you do the following in your script:
#!/bin/ksh
echo $1
You can also assign the positional parameter to a local variable for later use in your script like so:
#!/bin/ksh
param_one=$1
echo $param_one
You can call this with:
test_sh KLMN
Note that the spacing in the assignment is important -- do not use spaces.
I am tring this option
#!/bin/ksh
echo $1
awk '{FS="=";print $2}' $1
and on the command line
test_sh INSTANCE=LSN_MUM
but awk is failing.is there any problem over here?
Probably #!/bin/ksh -k will work (untested).

Variables that work everywhere

How can I set variables that work everywhere? My .bashrc has:
Questions='/Users/User/Stackoverflow/Questions'
Address='My address'
My file has:
$Questions
$Addres
The command "$ cat my_file" in Shell prints "$Questions" and "$Address", instead of "/Users/User/Stackoverflow/Questions" and "My address". Other places where I would like have the variables are Email and Browser. But I cannot get them working.
How can I have my variables to work in every program?
cat doesn't interpret variables. It simply prints out the contents of a file, byte-for-byte.
If you want to be able to print out the values of the variables with my_file, I would suggest changing it to read
echo "$Questions"
echo "$Address"
Then you can "source" it (kind of like running it in the current shell environment) with
$ source my_file
or
$ . my_file
You might also have to use export in .bashrc, like so:
export Questions='/Users/User/Stackoverflow/Questions'
export Address='My address'
How can I have my variables to work in every program?
You can't. Bash and cat are two separate programs. You set a bash variable, it doesn't mean that cat will behave like bash to interpret it. $VARNAME is a shell syntax, cat is a different program, that share almost nothing with the shell.
You can export the shell variable as an environment variable, but cat is not programmed to replace any text templates, it goes way beyond its purpose.
Instead, you may use sed to perform text template substitutions:
sed -e "s|#QUESTIONS#|$Questions|g; s|#ADDRESS#|$Address|g" file.txt
This will replace all instances of #QUESTIONS# and #ANSWERS# in the file with the contents of $Questions and $Address shell variables. Note that these shell variables must not contain any pipe ("|") symbols, since the suggestion uses them as delimiters.
You can get the "cat" thing to work using some nasty hackery:
eval "$(printf 'cat << END\n%s\nEND' "$(< foo)")"
Where "foo" is the file that contains your text you want the bash parameters expanded from. This solution basically just converts the text into a here document, which does expand bash parameters.
cat <<END
[your text]
END
Limitations:
You can't have a line with just "END" in the text file or the solution will break. It'll think the line with "END" in the text file ends the here document instead of the END in the printf command, and the ouput will end early.
TBH:
This is something you just shouldn't want to do. If you want to make template files, go find a templating system that's built for this. You shouldn't be raping bash into doing something that it isn't built to do. It's a scripting language, not a templating system. It's built to parse scripts with a well defined syntax, not arbitrary text files.
You can't. In order to do that, you'd need the cooperation of every email client writer, every browser writer, every utility writer.
Type env see if the variables exist.
If so, try calling them with ${VAR_NAME}.
After re-iterating I now see your problem. You just can't have a text file, cat out it's content and expect the environments variables to be parsed. You just can't.
If it was a bash script file, and you were to run it, you could echo out the variables and they would be parsed like you want.
From your comment on Paul Tomblin's answer:
Are you sure? I have heard that you can have all kind of things like RSS-reader in Emacs. Perhaps, there is a better cooperation. I am a VIM-user, so I don't know. If someone knows whether Emacs has great cooperation between programs, please do not hesitate to share your knowledge. – UnixBasics (3 mins ago)
Do you want (or would you be satisfied with) an editor that can expand your environment variables?
That is a different (i.e. simpler, and possible) problem.
On purely theoretical level, I suppose a hacked filesystem could do what you want, but it would certainly break all kinds of binary storage. So we add a filesystem flag for text (expandable) and non-text file types. And we'd need a way for the filesystem to know what set of variable to expand, and ad nauseum...
Just add to your ~/.profile or to ~/.bashrc:
export Questions='/Users/User/Stackoverflow/Questions'
export Address='My address'

Resources