250

I run across many shell scripts with variables in all caps, and I've always thought that there is a severe misunderstanding with that. My understanding is that, by convention (and perhaps by necessity long ago), environment variables are in all-caps.

But in modern scripting environments like Bash, I have always preferred the convention of lower-case names for temporary variables, and upper-case ones only for exported (i.e. environment) variables. For example:

#!/usr/bin/env bash
year=`date +%Y`
echo "It is $year."
export JAVA_HOME="$HOME/java"

That has always been my take on things. Are there any authoritative sources which either agree or disagree with this approach, or is it purely a matter of style?

codeforester
  • 34,080
  • 14
  • 96
  • 122
JasonSmith
  • 70,736
  • 21
  • 120
  • 147

9 Answers9

330

By convention, environment variables (PAGER, EDITOR, ...) and internal shell variables (SHELL, BASH_VERSION, ...) are capitalized. All other variable names should be lower case.

Remember that variable names are case-sensitive; this convention avoids accidentally overriding environmental and internal variables.

Keeping to this convention, you can rest assured that you don't need to know every environment variable used by UNIX tools or shells in order to avoid overwriting them. If it's your variable, lowercase it. If you export it, uppercase it.

codeforester
  • 34,080
  • 14
  • 96
  • 122
lhunath
  • 112,381
  • 16
  • 66
  • 75
  • 12
    +1. Good point about accidental overwriting. I forgot to mention, but now that you mention it, I think I decided on using lowercase because I read or heard about just that problem. – JasonSmith Mar 23 '09 at 16:23
  • 8
    I thought the main reason for using uppercase variable names was to avoid conflicts with shell commands. We recently had the hostname of one of our servers accidentally changed to '=' because a script used a variable 'hostname'. – ThisSuitIsBlackNot Sep 25 '11 at 18:06
  • 33
    @ThisSuitIsBlackNot Ignoring crappy code, variables are prefixed with a dollar when expanded and used in a place where they cannot be confused with a command name when they're not. Obviously, doing hostname = moo is going to land you in trouble. Not because you're using a lowercased "hostname", but because you're not using the correct assignment syntax. Assignment is done with hostname=moo, no spaces. Assuming correct code, you don't need to worry about variable names conflicting with command names. – lhunath Oct 21 '11 at 08:30
  • 6
    All the text books I've looked at always user upper case for all shell variables. While lower case variable names are permissible, uppercase is the convention. – Brian S. Wilson Nov 14 '16 at 15:00
  • 3
    I didn't know this, and I just lost a couple hrs. over using `USER="username"` in a bash script automating some remote commands over ssh instead of `user="username"`. Ugh! Glad I know now! – Gabriel Staples May 31 '18 at 02:31
  • `SHELL` is not an "internal shell variable". It is a value the user puts in their environment to indicate their preferred shell to other tools, similar to the way EDITOR, VISUAL. and PAGER are used to describe preferences. – William Pursell Jan 14 '20 at 14:44
  • 1
    The "rest assured that you don't need to know every environment variable" thing is overstated. Obviously you **will** need to be careful not to overwrite such variables with your *own* environment varialbes, if you use all-caps for those. It's still a good point, but "rest assured" is too strong. – mathguy May 04 '20 at 01:24
  • @BrianS.Wilson, it used to be common that everybody everywhere seemed to write all caps variables in whatever shell script. I've struggled to find a bash standard to suggest what's in this answer, but it's still a convention that I've practiced for years now, and that was after years of creating capital vars; doing it the way that you've seen in conventions in old books. Conventions can change, and sometimes do for good reason. Not to mention, there's no theoretical reason to have uppercase vars that I can think of unless a more experienced/longer-timer can explain why that convention started. – John Pancoast Mar 24 '21 at 17:29
  • And to add to my last answer, I can't find a reason one way or the other about var case in shell/bash scripts. It's almost as-if the built-ins and ENV vars and whatever else were capitalized so people just kind of created their bash vars as capital?? I honestly don't have another reason and would love to have one from someone who knows that history. Regardless, following the convention in this answer has another advantage: it makes my variable cases the same as literally all other languages I code in. That coupled with a bit more safety in regards to conflicts with env/other vars: I like it. – John Pancoast Mar 24 '21 at 17:38
  • 3
    @JohnPancoast, As a former Bell Labs employee, to the best of my knowledge, the convention was to ensure shell variables are easily distinguished from commands. It is still an extremely common practice to use the convention for the same reason. I have yet to see any published book, new or old, that don't follow this convention again for the sake of clarity. Having worked in many companies, I have dealt with shell code that used either format, and sometimes mixed the two. The use of lower case variables always made the scripts more difficult to work with IMHO. – Brian S. Wilson Mar 26 '21 at 01:12
  • @BrianS.Wilson, thanks that makes a lot of sense and well, if you were at Bell in those old days, you've settled the "long-timer" question :) No disrespect meant. And I will _definitely_ agree from my own experience of a couple decades around sys' and dev that capitalized snake case vars are _absolutely_ still a widely used convention for sure. The project I just joined has capitalized snake case, the last one had caps snake case, my own code throughout the years has morphed perhaps, and in the wild I've seen them both. – John Pancoast Mar 27 '21 at 17:16
  • 1
    @BrianS.Wilson So to simplify: the original convention of creating uppercase variables in `shell` scripts was most likely to keep variables from conflicting with commands. This newer convention is to use lowercase variables in `shell` scripts to keep them from conflicting with ENV variables. It's interesting, I've never had ENV var conflicts although I did still adopt this convention (for a couple reasons) but I'm rethinking it. It's an interesting one. Thank you for the enlightening answer. – John Pancoast Mar 27 '21 at 17:52
  • from a comment: `"Assuming correct code, you don't need to worry about variable names conflicting with command names."` from the Answer `"Remember that variable names are case-sensitive; this convention avoids accidentally overriding environmental and internal variables"` ... But since shell variables cannot overwrite environment variables using the assignment operator `=`, your argument seems incongruent with your assertion: `"All other variable names should be lower case."` No? – Seamus Mar 10 '22 at 09:38
48

Any naming conventions followed consistently will always help. Here are a few helpful tips for shell variable naming:

  • Use all caps and underscores for exported variables and constants, especially when they are shared across multiple scripts or processes. Use a common prefix whenever applicable so that related variables stand out and won't clash with Bash internal variables which are all upper case.

    Examples:

    • Exported variables with a common prefix: JOB_HOME JOB_LOG JOB_TEMP JOB_RUN_CONTROL
    • Constants: LOG_DEBUG LOG_INFO LOG_ERROR STATUS_OK STATUS_ERROR STATUS_WARNING
  • Use "snake case" (all lowercase and underscores) for all variables that are scoped to a single script or a block.

    Examples: input_file first_value max_amount num_errors

    Use mixed case when local variable has some relationship with an environment variable, like: old_IFS old_HOME

  • Use a leading underscore for "private" variables and functions. This is especially relevant if you ever write a shell library where functions within a library file or across files need to share variables, without ever clashing with anything that might be similarly named in the main code.

    Examples: _debug _debug_level _current_log_file

  • Avoid camel case. This will minimize the bugs caused by case typos. Remember, shell variables are case sensitive.

    Examples: inputArray thisLooksBAD, numRecordsProcessed, veryInconsistent_style


See also:

codeforester
  • 34,080
  • 14
  • 96
  • 122
  • 6
    This is *a* convention but it is hardly universally accepted. The rationale against camel case isn't entirely convincing. The recommendation to use SHOUTING for exported variables is mildly controversial. – tripleee Jul 06 '18 at 09:27
  • 6
    I didn't make a claim that it is a commonly followed convention. I have seen that most programmers don't think seriously about following strong conventions in shell scripts and thought of jotting down my thoughts based on what I have been doing. – codeforester Jul 06 '18 at 19:21
19

If shell variables are going to be exported to the environment, it’s worth considering that the POSIX (Issue 7, 2018 edition) Environment Variable Definition specifies:

Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2017 consist solely of uppercase letters, digits, and the underscore ( _ ) from the characters defined in Portable Character Set and do not begin with a digit.

...

The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities.

Anthony Geoghegan
  • 10,874
  • 5
  • 46
  • 55
7

I do what you do. I doubt there's an authoritative source, but it seems a fairly widespread de-facto standard.

Draemon
  • 32,863
  • 13
  • 73
  • 103
  • 1
    I agree. It's because ALL_CAPS is ugly, but it's good to make ENVIRONMENT VARIABLES stand out by being ugly. – slim Mar 23 '09 at 11:46
  • 3
    I agree with you on coding style, but I definitely disagree that it's widespread! Shell scripts are one of those side languages that people just learn informally, and so I feel like everybody is always saying LOCATION=`cat /tmp/location.txt` – JasonSmith Mar 23 '09 at 16:38
  • @jhs - I've obviously been lucky in the shell scripts I've had to work with! – Draemon Mar 23 '09 at 17:29
  • 5
    *"The name space of environment variable names containing lowercase letters is reserved for applications."* -- [POSIX IEEE Std 1003.1-2008 section 8.1](http://pubs.opengroup.org/onlinepubs/9699919799.2016edition/basedefs/V1_chap08.html) – tripleee Dec 19 '17 at 18:57
5

Actually, the term "environment variables" seems to be of fairly recent coinage. Kernighan and Pike in their classic book "The UNIX Programming Environment", published in 1984, speak only of "shell variables" - there is not even an entry for "environment" in the index!

  • 10
    I think that is a omission of the book. getenv(), setenv() and environ were introduced in UNIX version 7 (1979). http://en.wikipedia.org/wiki/Version_7_Unix – Juliano Mar 23 '09 at 16:05
  • 4
    That book looks to note that upper case variables do have special meaning. – ashawley Mar 23 '09 at 17:25
  • 1
    The functions in UNIX 7th Edition were `getenv()` and `putenv()`; `setenv()` and `unsetenv()` are more recent additions. – Jonathan Leffler Dec 22 '20 at 17:40
3

It's just a very widely held convention, I doubt there's any "authoritative" source for it.

Alnitak
  • 325,660
  • 70
  • 395
  • 481
2

i tend use ALL_CAPS both for environment and global variables. of course, in Bash there's no real variable scope, so there's a good portion of variables used as globals (mostly settings and state tracking), and relatively few 'locals' (counters, iterators, partly-constructed strings, and temporaries)

Javier
  • 58,927
  • 8
  • 76
  • 126
  • Yes, I kind of conceptually think of non-exported variables as locals, since Bash is so often forking child processes to do whatever it's tasked with doing. – JasonSmith Mar 23 '09 at 12:19
0

Bash, and most shell script interpreters, recognize global and local variables within functions (e.g typeset, declare, local) and should be used as appropriate. As previously commented, "Environment variable names used by the utilities in the Shell and Utilities volume of POSIX.1-2017 consist solely of uppercase letters, digits, and the underscore ( _ ) from the characters defined in Portable Character Set and do not begin with a digit. ... The name space of environment variable names containing lowercase letters is reserved for applications. Applications can define any environment variables with names from this name space without modifying the behavior of the standard utilities." (POSIX IEEE Std 1003.1-2008 section 8.1 )

Brian S. Wilson
  • 491
  • 4
  • 9
-1

ALL_CAP IS TOO UGLY TO FAST RECOGNIZE !!!!!!!!!!!!!!!!!!!!!

enter image description here ref: https://uxmovement.com/content/all-caps-hard-for-users-to-read

for my own config, I use whatever I want:

  export XDG_CONFIG_HOME=$( realpath "$HOME/.config" )                                                                                                                                           
  export XDG_CACHE_HOME=$( realpath "$HOME/d/.cache_wf" )
  export XDG_DATA_HOME=$( realpath "$HOME/.local/share" )

  # 全部大写, 难辨认, 用这个:
  export cfg_X=$XDG_CONFIG_HOME
  export cache_X=$XDG_CACHE_HOME
  export data_X=$XDG_DATA_HOME

  [ -d "$cfg_X" ] || mkdir -m 0750 -p "$cfg_X"
  [ -d "$cache_X" ]  || mkdir -m 0750 -p "$cache_X"
  [ -d "$data_X" ]   || mkdir -m 0750 -p "$data_X"

(And I prefer screenshot to pasted text, because of color and format)

enter image description here

Good Pen
  • 437
  • 4
  • 7