0

What is "declare" in Bash?

declare -r is_debug true
if [ "$is_debug" = true ]; then
    printf "%s\n", "is debug"
else
    printf "%s\n", "is not debug"
fi

declare -p is_debug echo "${is_debug-isunset}"

output:

jian@jian:~/Desktop/pg_src/src4/postgres$ bash /home/jian/scratch/scratchpads/47a6066b9dfaca1c2b13ea2e99f4e929/scratch.sh
is not debug
,declare -r is_debug
isunset
jian@jian:~/Desktop/pg_src/src4/postgres$ bash --version
GNU bash, version 5.1.16(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2020 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.

declare -p is_debug echo "${is_debug-isunset}"

i am confused with ,declare -r is_debug output. i expect it return declare -r is_debug.

jian
  • 567
  • @steeldriver thanks. I use this in other cases. really thanks for point it out! indirectly helped me – jian Jan 06 '24 at 02:33
  • See the extra paragraphs that I've added to my answer since you accepted it which might help further clear your confusion. – Stéphane Chazelas Jan 06 '24 at 10:32
  • You asked for a comma after the newline in your printf format (%s\n,). So you shouldn't be surprised that it's printed. – Toby Speight Jan 16 '24 at 14:15

1 Answers1

6
declare -r is_debug true

Declares two read-only variables is_debug and true without setting their values. Unless called within a function, they will retain their original value if any. If called within a function, a new local variable with no value will be instantiated (unless the variable had already been declared beforehand in that scope with local/typeset/declare).

You likely want:

declare -r is_debug=true

Or more portably (and not making the variable local if called within a function):

readonly is_debug=true
printf "%s\n", "is debug"

Same as:

printf '%s\n,' "is debug"

Or

printf 'is debug\n,'

Prints is debug followed by a newline followed by a comma, that comma not being followed by a newline, so the next thing that is output will be appended to that.

You likely want:

printf '%s\n' 'is debug'

Or:

printf 'is debug\n'

Or:

echo 'is debug'

(which adds the newline by itself)

Or:

echo is debug

as echo happens to join its arguments with one space before printing them.

While printf is generally better (more reliable and portable) than echo, there's no problem with using echo in this case as we know the first argument doesn't start with -, all arguments contain ASCII-only characters and no backslash.

Comma is used to separate things in csh-style brace expansion:

$ echo {a,b}c
ab ac

Here, except in zsh, you could (not that you should) write it:

$ {echo,is,debug}
is debug

And in Korn-style arithmetic expressions (a C-like syntax)

$ echo "$(( (a = 6), (b = 7), a * b ))"
42

(not all shells support , in their arithmetic expressions and note than in ksh93 it may conflict with the , floating point radix character in locales where it's comma instead of dot).

But is otherwise not used to separate arguments to commands. Arguments to commands are separated by blanks (in the case of bash, the characters that are classified as blank in the locale and that are encoded on one byte, which includes space, tab and sometimes the non-breaking space character).

Maybe, you were confusing with the printf function of the awk language which is also C-like. In awk, you'd write:

BEGIN{printf "%s %d\n", "string", number}

Like in C you'd write:

printf("%s %d\n", "string", number);

(the parenthesis can also be used in awk).

But the syntax of the shell language is quite different from that of most other languages and in particular C/awk.

In shells, quotes are not used to introduce string constants (everything is string in shells) but to remove the special meaning that some characters have in the language.

For instance, in:

printf '%s\n' 'is debug'

The quotes (here using single quotes as the "..." ones are better reserved for things that include expansions) are used to remove their special meaning to the shell to the backslash character (which is also a quoting operator in the syntax of the shell) and the space character, which is used to separate arguments to commands as we saw.

We could also quote everything but the characters that need to retain their special meaning:

'printf' '%s\n' 'is debug'

Or:

\p\r\i\n\t\f \%\s\\\n \i\s\ \d\e\b\u\g

Where all the characters except the two spaces that separate those 3 arguments are quoted.

Or quote only the ones that need to lose their special meaning:

printf %s'\'n is' 'debug

Or:

printf %s\\n is\ debug

That's all shell syntax that will end up doing exactly the same thing: run the printf command with printf, %s\n and is debug as three separate arguments.

And I hope it should clarify why moving that comma in or out of the quotes makes absolutely no difference, that comma having no special meaning in the shell syntax as it's not used as part of brace expansion or inside an arithmetic expression.

For more details as to what the special characters and quoting operators are in various shells, see: How to use a special character as a normal one in Unix shells?