views:

244

answers:

7

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?

A: 

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.

Yuval A
Won't work in "cat" or email or a browser.
Paul Tomblin
+1  A: 

You can't. In order to do that, you'd need the cooperation of every email client writer, every browser writer, every utility writer.

Paul Tomblin
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.
Masi
I don't see how the presence of a particular extension to a particular editor has any bearing on variables working "everywhere". Emacs has an RSS reader because Emacs has a programming language built in (elisp) and somebody wrote something in elisp.
Paul Tomblin
@Paul Tomblin Thanks for clarification. Is there some programs that solely handles "cooperation"? Perhaps, it is a solution to get variables to work between programs. What are such programs called?
Masi
+5  A: 

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'
David Zaslavsky
I cannot get the "source"-command working. Do you need "#!/bin/sh" to the file that contains the echo-commands?
Masi
Nope, not if you're just sourcing it. The "#!/bin/sh" line is only necessary if you make the file executable and try to run it as a program.
David Zaslavsky
David Thank you!
Masi
+2  A: 

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.

Juliano
+1, Saved me the time of writing about sed
jhs
A: 

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...

dmckee
Sounds very interesting. The words "hacked [fs]" makes me wondering. I cannot understand why the variables would break.
Masi
Binary storage would break whenever your video file (say) contained the byte sequence "$IMPORTANTVARIABLE", because this hypothetical filesystem would intercept this byte string, interpret it, and send the *wrong* data to the video player. In short: what your asking for is horribly ill-conceived.
dmckee
+1  A: 

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.

lhunath
A: 

Just add to your ~/.profile or to ~/.bashrc:

export Questions='/Users/User/Stackoverflow/Questions'
export Address='My address'
kzing