34

What is the difference between these three commands?

echo `date`
echo "`date`"
echo '`date`'

I am confused on what the differences actually are. I think that when the ' are around it means that it is a string, therefore echo would literally output the string date instead of displaying the date?

4 Answers 4

29

`date` will just expand to the output of the date command. However, it removes extra space characters at places where there are more than one consecutive space character in the output. (This is because the command substitution is subject to word splitting, and because of how the echo command handles multiple arguments.)

In "`date`", the double quotes are weak quotes, so they will expand variables (try "$PWD") and perform command substitution. The result of the expansion is passed as a single argument to the echo command, with any consecutive spaces included: that is, word splitting is not performed.

In '`date`', the single quotes are stronger quotes, so they will not allow expansion of variables or command substitution within them.

Refer this link for more explanation.

Edited the first point as correctly pointed by Michael Suelmann in the comment below.

9
  • 1
    What exactly is the ` character that is surrounding date called? If I am understanding correctly, meta characters will not work in single quotations?
    – John
    Commented Nov 1, 2013 at 6:27
  • If I am understanding correctly, meta characters will not work in single quotations?
    – John
    Commented Nov 1, 2013 at 6:46
  • 8
    The ` is often called a "backtick" in that scenario and various Unix documentation/books. It's not actually being used as a Unicode grave accent when it's on its own like that, even though that's the name of the symbol. And you're correct that no expansion of metacharacters/expressions will occur if you surround it with single quotes. Commented Nov 1, 2013 at 6:55
  • Your first statement is incorrect as the output might be slightly different depending on the date or locale. Only the second command will output the same thing as the bare date command.
    – jlliagre
    Commented Nov 1, 2013 at 8:08
  • 1
    @BonsiScott The extra space between "Nov" and "1" is removed in HTML as well ;)
    – Izkata
    Commented Nov 1, 2013 at 15:53
23

Both

echo `date`

and

echo "`date`"

will display the date. The output from the latter looks like the output from running date by itself.

There's a difference, though: the one surrounded in " quotes " will be sent to to echo as a single argument. The quotes encapsulate the output of the entire command as one argument. Since echo just prints out its arguments in order, with spaces in between, it will basically look the same.

Here's an example of the subtle difference:

echo `date`

produces:

Fri Nov 1 01:48:45 EST 2013

but:

echo "`date`"

produces:

Fri Nov  1 01:48:49 EST 2013

Note that the two spaces after Nov were reduced to one without the quotes. This is because the shell is parsing each space-separated element and sending the result to echo as 6 arguments. When you quote it, echo receives one single argument and the quotes retain the space.

This becomes much more important in commands other than echo. For example, imagine a command foo that wants two arguments: a date, and an email address.

This will work in that scenario:

foo "`date`" [email protected]

But this will confuse the script by sending it 7 arguments:

foo `date` [email protected]
2
  • 3
    You are self contradicting in your first sentence. The first and second form won't always output the same thing as you demonstrate later.
    – jlliagre
    Commented Nov 1, 2013 at 8:10
  • Thanks. I've changed up the wording to make it more clear. Commented Nov 1, 2013 at 16:13
4

In POSIX shells, `date` is the ancient form of command substitution. The modern syntax is $(date).

In both cases, they expand to the output of date with the trailing newline characters stripped (provided that output doesn't contain NUL characters).

However, when not within double quotes and in list contexts (for instance in arguments to simple commands like echo in your case), that expansion is further subject to:

  1. Word splitting: that is the "output of date with the trailing newline characters stripped" is split according to the current value of the $IFS variable (by default containing space, tab and newline (and NUL with zsh)) into several words.

    For instance, if date outputs Fri 1 Nov 14:11:15 GMT 2013\n (like it often does in an English locale and in a mainland British timezone), and $IFS currently contains :, that will be split into 3 words: Fri 1 Nov 14, 11 and 15 GMT 2013.

  2. Filename generation (aka globbing) (except with zsh): that is, each word resulting from the splitting above is looked for wildcard characters (*, ?, [...] though some shells have more), and expanded to the list of filenames that match those patterns. For instance, if the output of date is ?%? 33 */*/* UVC 3432 (like it often is in Venusian locales and UVC timezone), and $IFS is the default value), then that expands to all the non-hidden 3 character filenames in the current directory whose middle character is %, 33, all the non-hidden files in all the non-hidden subdirectories of all the non-hidden subdirectories of the current directory, UVC and 3432.

That is why:

  1. You should always quote (with double quotes) command substitutions unless you do want either the word splitting or the filename generation performed upon its expansion
  2. If you do want word splitting, then you should set $IFS to the characters you want to split on.
  3. Except in zsh, if you do want word splitting but not filename generation, you need to issue a set -o noglob (aka set -f) to disable it.

The single quotes quote everything so cause the backtick characters to be taken literally.

Example (using -o xtrace makes it easier to see what's going on):

$ bash --norc -o xtrace
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri  1 Nov 14' 42 '33 GMT 2013'
Fri  1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri  1 Nov 14:42:41 GMT 2013'
Fri  1 Nov 14:42:41 GMT 2013

bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS     # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
?%? 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432

If the output contains NUL characters, then the behaviour varies from shell to shell: some remove them, some truncate the output at the first NUL character, zsh preserves them but note that anyway external commands cannot take arguments containing NULs

0
0

With `date` you get the output of date split into multiple words, because word splitting is done after command substitution.

With "`date`" you get the output of date as one word/parameter as there is command substitution between double quotes, but the output is not parsed further. The same is valid with variable expansion like "$i" in my example below.

With '`date`' you get a literal `date` as there is no command substitution between single quotes.

Perhaps the differences of the 3 forms will be more visible this way:

> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013

> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013

> for i in '`date`'; do echo "$i"; done
`date`

You must log in to answer this question.

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