15

Is it good shell programming practice to use read-only variables whenever possible or does it have any drawbacks? E.g. if I wanted to write some script that consists of multiple script files that make use of immutable file paths, would it make sense to declare the paths like that:

readonly LOGS
export LOGS 
LOGS="/some/path"

Another question: Is it a good idea to split monolithic and tedious too read shell script code into separate files? Many thanks for your answers.

user1812379
  • 827
  • 3
  • 11
  • 22
  • 2
    So far, I haven't seen any bashism that would be good programming practice. If you want to learn clean shell scripting, stay with plain `sh`. What can't be easily done this way, should neither be done with bash. – Jo So Nov 16 '12 at 01:14
  • Read only variables can be useful for security purposes. To see why, set a readonly variable on the command line and then see how difficult it is to try to change it - the last time I checked you have to hack Bash with a debugger (e.g. `gbd attach `) to be able to change a read only variable value. –  Apr 01 '15 at 03:26
  • @A.Danischewski - or just start up a new shell process. – Mark Reed Jun 02 '15 at 12:53

4 Answers4

17

It sounds like you might think that readonly does more than it really does. For one thing, readonly status is not exported into the environment or inherited by child processes:

$ declare -rx LOGS=hello
$ LOGS=goodbye
bash: LOGS: readonly variable
$ bash -c 'echo "$LOGS"'
hello
$ bash -c 'LOGS=goodbye; echo "$LOGS"'
goodbye
$ 
Mark Reed
  • 91,912
  • 16
  • 138
  • 175
  • 1
    excellent point, but one could easily work around that by using "." instead of calling the script as a child process. – figtrap Nov 07 '16 at 20:45
7

A classic use of read-only variables is with TMOUT. Setting this variable to a non-zero value will logout an interactive terminal session after TMOUT seconds of inactivity (i.e. no keyboard input). To defeat a smart user from overriding the setting, use readonly:

readonly TMOUT=60

Having done this, there is no way to do:

export TMOUT=0
JRFerguson
  • 7,426
  • 2
  • 32
  • 36
  • 3
    Easily worked around with `exec bash`. With `--norc` if necessary to keep `TMOUT` from being set again. – Mark Reed Nov 22 '16 at 13:14
6

Generally speaking, using read only variables (in any language) and modularizing your program (in any language) is a good thing.

Read only variables protect against a common source of bugs, and helps improve readability and maintainability. Knowing that you can rely on a value of a variable enables you to reason better about your program, and to make assumptions about that variable later on -- things you couldn't do if the variable were mutable.

Modularization improves maintainability and re-usability. More modules generally means more fine-grained units that can find re-use in different circumstances, shorter code that's easier to read, and if your modules are independent, less interactions among parts that could wreck a modification.

RonaldBarzell
  • 3,822
  • 1
  • 16
  • 23
2

I don't think readonly variables in bash are useful. I can't think of any issue I've seen that could have been prevented by making a variable readonly. Such limitations goes against the dynamic nature of bash. There are other more common causes of issues (like mispellings or forgetting to declare variables as local) which are impossible to prevent anyway.

If you want to split things off try to only split "functions", not just chunks of code. It's easier to reuse a small thing if you know "source ~/myscript.sh" doesn't actually do anything.

cdleonard
  • 6,570
  • 2
  • 20
  • 20
  • 1
    Thanks. But read-only variables don't have any disadvantages, do they? – user1812379 Nov 15 '12 at 20:42
  • 5
    Actually readonly variables have their value. If you maintain tens of scripts which are cross sourced then marking a variable as immutable makes a lot of sense! As @MarkReed mentioned they are not really immutable, but when somebody else start reading your "stuff" they will have the intention that this variable is not meant to change ! This is really useful and makes scripts much more readable. I truly believe sharing a state in global variables is an awful practice, but as we all know bash is not designed with any of this in mind. – egelev Jun 02 '15 at 12:16