Can I safely omit quotes on the right side of a local assignment?

function foo {
    local myvar=${bar}

I'm mainly interested in bash, but any info on corner cases in other shells are welcome.


2 Answers 2


Quotes are needed in export foo="$var" or local foo="$var" (or readonly, typeset, declare and other variable declaring commands) in:

  • dash versions 0.3.8-15 to (see change).
  • the sh of NetBSD (also based on the Almquist shell).
  • The sh of FreeBSD 9.2 or older (see the change in 9.3)
  • yash
  • zsh with versions prior to 5.1 in ksh or sh emulation (or for export var="$(cmd)" where zsh would perform word splitting otherwise (not globbing)).

As otherwise the variable expansion would be subject to word splitting and/or filename generation like in any argument to any other command.

And are not needed in:

  • bash
  • ksh (all implementations)
  • the sh of FreeBSD 9.3 or newer
  • busybox' ash-based sh (since 2005)
  • zsh
  • dash 0.5.11 or newer.

In zsh, split+glob is never done upon parameter expansion, unless in sh or ksh emulation, but split (not glob) is done upon command substitution. Since version 5.1, export/local and other declaration commands have become dual keyword/builtin commands like in the other shells above, which means quoting is not necessary, even in sh/ksh emulation and even for command substitution.

There are special cases where quoting is needed even in those shells though like:

a="b=some value"
export "$a"

Or more generally, if anything left of the = (including the =) is quoted or the result of some expansion (like export 'foo'="$var", export foo\="$var" or export foo$((n+=1))="$var" (that $((...)) should also be quoted actually)...). Or in other words when the argument to export wouldn't be a valid variable assignment if written without the export.

If the export/local command name itself is quoted (even in part like "export" a="$b", 'ex'port a="$b", \export a="$b", or even ""export a="$b"), the quotes around $b are needed except in AT&T ksh, mksh and recent versions of dash.

If export/local or some part of it is the result of some expansion (like in cmd=export; "$cmd" a="$b" or even export$(:) a="$b") or in things like dryrun=; $dryrun export a="$b"), then the quotes are needed except in recent versions of dash.

In the case of > /dev/null export a="$b", the quotes are needed in pdksh and some of its derivatives.

For command export a="$b", the quotes are needed in every shell but mksh, ksh93, recent dash, and bash -o posix (with the same caveats about command and export not being the result of some expansion in shells other than dash).

They are not needed in any shell when written:

foo=$var export foo

(that syntax being also compatible with the Bourne shell but in recent versions of zsh, only working when in sh/ksh emulation).

(note that var=value local var shouldn't be used as the behaviour varies across shells).

Also note that using export with an assignment also means that the exit status of cmd in export var="$(cmd)" is lost. Doing it as export var; var=$(cmd) doesn't have that problem.

Also beware of this special case with bash:

$ bash -c 'IFS=; export a="$*"; echo "$a"' bash a b
$ bash -c 'IFS=; export a=$*; echo "$a"' bash a b
a b

My advice would be to always quote.

  • 3
    Note that in zsh quotes are needed for local foo="$(cmd)" because wordsplitting (but not filename generation) is performed for unquoted command substitutions (but not for unquoted parameter expansions), unless KSH_TYPESET is enabled, in which case quotes aren't needed. Make sense? No? Then always quote everything unless you know exactly what you're doing.
    – Matt
    Commented Oct 25, 2013 at 17:39
  • 3
    @Matt, I love your conclusion. :D It's funny, most of what I've learned of shell scripting came from this stackexchange, so that I didn't realize that always quote your variables is not common knowledge amongst script writers. I'm finding I have a lot of fixing up to do of existing production scripts written by people who didn't quote, and didn't know exactly what they were doing....
    – Wildcard
    Commented Jan 6, 2016 at 4:09
  • I don't think that dash actually need quoting on assignment: $ echo $SHELL; FOO="foo bar"; BAR=$FOO; echo $BAR; f () { local BAZ="baz quux"; local QUUX=$BAZ; echo $QUUX; }; f yields /bin/dash, foo bar, and baz quux Commented Dec 15, 2020 at 23:21
  • Thanks @EmanueleAina. It looks like it changed recently. See edit. Commented Dec 16, 2020 at 6:54

I generally quote any usage of variables where there might be characters such as white spaces. Otherwise you'll run into problems like this:


bar="hi bye"

function foo {
  local myvar=${bar}
  printf "%s\n" $myvar
  printf "%s\n" "$myvar"


The usage of the variable in an assignment doesn't appear to need the quotes, but when you go to use it such as in the printf you'll need it quoted there:

  printf "%s\n" "$myvar"

NOTE: Remember that the variable $IFS is what governs what the separator characters are.

IFS    The  Internal  Field  Separator that is used for word splitting after 
       expansion and to split lines into words with the read builtin command. 
       The default value is ``<space><tab><newline>''.


With debugging enabled in Bash we can see what's happening behind the scenes.

$ bash -x cmd.bash 
+ bar='hi bye'
+ foo
+ local 'myvar=hi bye'
+ printf '%s\n' hi bye
+ printf '%s\n' 'hi bye'
hi bye

In the above we can see that the variable, $bar was handed off fine to $myvar but then when we went to use $myvar we had to be cognoscente of the contents of $myvar when we went to use it.

  • 2
    word splitting is not the only problem with unquoted variables, you have to consider filename generation (aka globbing) as well (though that (both) doesn't apply in variable assignments and for bash and ksh in local/typeset... special builtins). Commented Oct 25, 2013 at 13:58

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .