Skip to main content
added 294 characters in body
Source Link
Stéphane Chazelas
  • 584.9k
  • 96
  • 1.1k
  • 1.7k

That would be the first time I see anybody complaining about that (we more often see people complaining about it not doing word splitting upon parameter expansion).

Most people expect

echo $file

to output the content of the $file variable and are annoyed when shells like bash don't (a behaviour inherited from the Bourne shell, unfortunately not fixed by ksh and specified by POSIX for the sh interpreter), and that's causing a lot of bugs and security vulnerabilities and that's why you need to quote all the variables in those shells.

See for instance: Security implications of forgetting to quote a variable in bash/POSIX shells

I see that you're expecting that too as you're writing echo $0 and not echo "$0".

zsh has fixed that. It does neither globbing nor word splitting by default upon parameter expansion. You need to request those explicitly:

  • echo $=file: perform word splitting
  • echo $~file: perform globbing
  • echo $=~file: perform both

Or you could turn on the globsubst and shwordsplit options to get the same behaviour as in Bourne-like shells (those two options are enabled when zsh is invoked as sh for sh compatibility), but I would not recommend that unless you need zsh to interpret code written for another shell (and even in that case, it would make more sense to interpret that code in sh emulation in a local context with emulate -L sh).

Here naming your variable file in

file=*

is misleading if you intend it to be expanded upon expansion¹assignment¹.

filename_pattern=*

would make more sense. If you want a variable holding the name of all the non-hidden files in the current directory, you'd do:

files=(*)

or:

files=( *(N) )

for that assignment not to fail if there's no non-hidden file in the current directory.

That is, use an array variable assignment. That (file=(*)) would work the same as in bash or ksh93², mksh or yash, except that zsh doesn't have that other misfeature of the Bourne shell whereby the pattern is left unexpanded when there's no match.


¹Note¹ Note that * is a perfectly valid name for a file on Unix-like system. I take some comfort in that rm -f -- $file removes the file whose name is stored in $file even if that file is called *.

² ksh93 has files=( ~(N)* ) as an equivalent of zsh's files=( *(N) ) though and bash and yash, like zsh also have a nullglob option which you can enable globally to apply that to every glob expansion (though that's not what you want in the general case).

That would be the first time I see anybody complaining about that (we more often see people complaining about it not doing word splitting upon parameter expansion).

Most people expect

echo $file

to output the content of the $file variable and are annoyed when shells like bash don't (a behaviour inherited from the Bourne shell, unfortunately not fixed by ksh and specified by POSIX for the sh interpreter), and that's causing a lot of bugs and security vulnerabilities and that's why you need to quote all the variables in those shells.

See for instance: Security implications of forgetting to quote a variable in bash/POSIX shells

I see that you're expecting that too as you're writing echo $0 and not echo "$0".

zsh has fixed that. It does neither globbing nor word splitting by default upon parameter expansion. You need to request those explicitly:

  • echo $=file: perform word splitting
  • echo $~file: perform globbing
  • echo $=~file: perform both

Or you could turn on the globsubst and shwordsplit options to get the same behaviour as in Bourne-like shells (those two options are enabled when zsh is invoked as sh for sh compatibility), but I would not recommend that unless you need zsh to interpret code written for another shell (and even in that case, it would make more sense to interpret that code in sh emulation in a local context with emulate -L sh).

Here naming your variable file in

file=*

is misleading if you intend it to be expanded upon expansion¹

filename_pattern=*

would make more sense. If you want a variable holding the name of all the non-hidden files in the current directory, you'd do:

files=(*)

or:

files=(*(N))

for that assignment not to fail if there's no non-hidden file in the current directory.

That is, use an array variable assignment. That (file=(*)) would work the same as in bash or ksh93, mksh or yash, except that zsh doesn't have that other misfeature of the Bourne shell whereby the pattern is left unexpanded when there's no match.


¹Note that * is a perfectly valid name for a file on Unix-like system. I take some comfort in that rm -f -- $file removes the file whose name is stored in $file even if that file is called *.

That would be the first time I see anybody complaining about that (we more often see people complaining about it not doing word splitting upon parameter expansion).

Most people expect

echo $file

to output the content of the $file variable and are annoyed when shells like bash don't (a behaviour inherited from the Bourne shell, unfortunately not fixed by ksh and specified by POSIX for the sh interpreter), and that's causing a lot of bugs and security vulnerabilities and that's why you need to quote all the variables in those shells.

See for instance: Security implications of forgetting to quote a variable in bash/POSIX shells

I see that you're expecting that too as you're writing echo $0 and not echo "$0".

zsh has fixed that. It does neither globbing nor word splitting by default upon parameter expansion. You need to request those explicitly:

  • echo $=file: perform word splitting
  • echo $~file: perform globbing
  • echo $=~file: perform both

Or you could turn on the globsubst and shwordsplit options to get the same behaviour as in Bourne-like shells (those two options are enabled when zsh is invoked as sh for sh compatibility), but I would not recommend that unless you need zsh to interpret code written for another shell (and even in that case, it would make more sense to interpret that code in sh emulation in a local context with emulate -L sh).

Here naming your variable file in

file=*

is misleading if you intend it to be expanded upon assignment¹.

filename_pattern=*

would make more sense. If you want a variable holding the name of all the non-hidden files in the current directory, you'd do:

files=(*)

or:

files=( *(N) )

for that assignment not to fail if there's no non-hidden file in the current directory.

That is, use an array variable assignment. That (file=(*)) would work the same as in bash or ksh93², mksh or yash, except that zsh doesn't have that other misfeature of the Bourne shell whereby the pattern is left unexpanded when there's no match.


¹ Note that * is a perfectly valid name for a file on Unix-like system. I take some comfort in that rm -f -- $file removes the file whose name is stored in $file even if that file is called *.

² ksh93 has files=( ~(N)* ) as an equivalent of zsh's files=( *(N) ) though and bash and yash, like zsh also have a nullglob option which you can enable globally to apply that to every glob expansion (though that's not what you want in the general case).

array=(...) is from zsh, not ksh93
Source Link
Stéphane Chazelas
  • 584.9k
  • 96
  • 1.1k
  • 1.7k

That would be the first time I see anybody complaining about that (we more often see people complaining about it not doing word splitting upon parameter expansion).

Most people expect

echo $file

to output the content of the $file variable and are annoyed when shells like bash don't (a behaviour inherited from the Bourne shell, unfortunately not fixed by ksh and specified by POSIX for the sh interpreter), and that's causing a lot of bugs and security vulnerabilities and that's why you need to quote all the variables in those shells.

See for instance: Security implications of forgetting to quote a variable in bash/POSIX shells

I see that you're expecting that too as you're writing echo $0 and not echo "$0".

zsh has fixed that. It does neither globbing nor word splitting by default upon parameter expansion. You need to request those explicitly:

  • echo $=file: perform word splitting
  • echo $~file: perform globbing
  • echo $=~file: perform both

Or you could turn on the globsubst and shwordsplit options to get the same behaviour as in Bourne-like shells (those two options are enabled when zsh is invoked as sh for sh compatibility), but I would not recommend that unless you need zsh to interpret code written for another shell (and even in that case, it would make more sense to interpret that code in sh emulation in a local context with emulate -L sh).

Here naming your variable file in

file=*

is misleading if you intend it to be expanded upon expansion¹

filename_pattern=*

would make more sense. If you want a variable holding the name of all the non-hidden files in the current directory, you'd do:

files=(*)

or:

files=(*(N))

for that assignment not to fail if there's no non-hidden file in the current directory.

That is, use an array variable assignment. That (file=(*)) would work the same as in bash or ksh93 (where that syntax comes from), mksh or yash, except that zsh doesn't have that other misfeature of the Bourne shell whereby the pattern is left unexpanded when there's no match.


¹Note that * is a perfectly valid name for a file on Unix-like system. I take some comfort in that rm -f -- $file removes the file whose name is stored in $file even if that file is called *.

That would be the first time I see anybody complaining about that (we more often see people complaining about it not doing word splitting upon parameter expansion).

Most people expect

echo $file

to output the content of the $file variable and are annoyed when shells like bash don't (a behaviour inherited from the Bourne shell, unfortunately not fixed by ksh and specified by POSIX for the sh interpreter), and that's causing a lot of bugs and security vulnerabilities and that's why you need to quote all the variables in those shells.

See for instance: Security implications of forgetting to quote a variable in bash/POSIX shells

I see that you're expecting that too as you're writing echo $0 and not echo "$0".

zsh has fixed that. It does neither globbing nor word splitting by default upon parameter expansion. You need to request those explicitly:

  • echo $=file: perform word splitting
  • echo $~file: perform globbing
  • echo $=~file: perform both

Or you could turn on the globsubst and shwordsplit options to get the same behaviour as in Bourne-like shells (those two options are enabled when zsh is invoked as sh for sh compatibility), but I would not recommend that unless you need zsh to interpret code written for another shell (and even in that case, it would make more sense to interpret that code in sh emulation in a local context with emulate -L sh).

Here naming your variable file in

file=*

is misleading if you intend it to be expanded upon expansion¹

filename_pattern=*

would make more sense. If you want a variable holding the name of all the non-hidden files in the current directory, you'd do:

files=(*)

or:

files=(*(N))

for that assignment not to fail if there's no non-hidden file in the current directory.

That is, use an array variable assignment. That would work the same as in bash or ksh93 (where that syntax comes from) mksh or yash, except that zsh doesn't have that other misfeature of the Bourne shell whereby the pattern is left unexpanded when there's no match.


¹Note that * is a perfectly valid name for a file on Unix-like system. I take some comfort in that rm -f -- $file removes the file whose name is stored in $file even if that file is called *.

That would be the first time I see anybody complaining about that (we more often see people complaining about it not doing word splitting upon parameter expansion).

Most people expect

echo $file

to output the content of the $file variable and are annoyed when shells like bash don't (a behaviour inherited from the Bourne shell, unfortunately not fixed by ksh and specified by POSIX for the sh interpreter), and that's causing a lot of bugs and security vulnerabilities and that's why you need to quote all the variables in those shells.

See for instance: Security implications of forgetting to quote a variable in bash/POSIX shells

I see that you're expecting that too as you're writing echo $0 and not echo "$0".

zsh has fixed that. It does neither globbing nor word splitting by default upon parameter expansion. You need to request those explicitly:

  • echo $=file: perform word splitting
  • echo $~file: perform globbing
  • echo $=~file: perform both

Or you could turn on the globsubst and shwordsplit options to get the same behaviour as in Bourne-like shells (those two options are enabled when zsh is invoked as sh for sh compatibility), but I would not recommend that unless you need zsh to interpret code written for another shell (and even in that case, it would make more sense to interpret that code in sh emulation in a local context with emulate -L sh).

Here naming your variable file in

file=*

is misleading if you intend it to be expanded upon expansion¹

filename_pattern=*

would make more sense. If you want a variable holding the name of all the non-hidden files in the current directory, you'd do:

files=(*)

or:

files=(*(N))

for that assignment not to fail if there's no non-hidden file in the current directory.

That is, use an array variable assignment. That (file=(*)) would work the same as in bash or ksh93, mksh or yash, except that zsh doesn't have that other misfeature of the Bourne shell whereby the pattern is left unexpanded when there's no match.


¹Note that * is a perfectly valid name for a file on Unix-like system. I take some comfort in that rm -f -- $file removes the file whose name is stored in $file even if that file is called *.

added 194 characters in body
Source Link
Stéphane Chazelas
  • 584.9k
  • 96
  • 1.1k
  • 1.7k

That would be the first time I see anybody complaining about that (we more often see people complaining about it not doing word splitting upon parameter expansion).

Most people expect

echo $file

to output the content of the $file variable and are annoyed when shells like bash don't (a behaviour inherited from the Bourne shell, unfortunately not fixed by ksh and specified by POSIX for the sh interpreter), and that's causing a lot of bugs and security vulnerabilities and that's why you need to quote all the variables in those shells.

See for instance: Security implications of forgetting to quote a variable in bash/POSIX shells

I see that you're expecting that too as you're writing echo $0 and not echo "$0".

zsh has fixed that. It does neither globbing nor word splitting by default upon parameter expansion. You need to request those explicitly:

  • echo $=file: perform word splitting
  • echo $~file: perform globbing
  • echo $=~file: perform both

Or you could turn on the globsubst and shwordsplit options to get the same behaviour as in Bourne-like shells (those two options are enabled when zsh is invoked as sh for sh compatibility), but I would not recommend that unless you need zsh to interpret code written for another shell (and even in that case, it would make more sense to interpret that code in sh emulation in a local context with emulate -L sh).

Here naming your variable file in

file=*

is misleading if you intend it to be expanded upon expansion¹

filename_pattern=*

would make more sense. If you want a variable holding the name of all the non-hidden files in the current directory, you'd do:

files=(*)

or:

files=(*(N))

for that assignment not to fail if there's no non-hidden file in the current directory.

That is, use an arrayarray variable assignment. That would work thatthe same as in bash or ksh93 (where that syntax comes from) mksh or yash, except that zsh doesn't have that other misfeature of the Bourne shell whereby the pattern is left unexpanded when there's no match.


¹Note that * is a perfectly valid name for a file on Unix-like system. I take some comfort in that rm -f -- $file removes the file whose name is stored in $file even if that file is called *.

That would be the first time I see anybody complaining about that (we more often see people complaining about it not doing word splitting upon parameter expansion).

Most people expect

echo $file

to output the content of the $file variable and are annoyed when shells like bash don't (a behaviour inherited from the Bourne shell), and that's causing a lot of bugs and security vulnerabilities and that's why you need to quote all the variables in those shells.

See for instance: Security implications of forgetting to quote a variable in bash/POSIX shells

I see that you're expecting that too as you're writing echo $0 and not echo "$0".

zsh has fixed that. It does neither globbing nor word splitting by default upon parameter expansion. You need to request those explicitly:

  • echo $=file: perform word splitting
  • echo $~file: perform globbing
  • echo $=~file: perform both

Or you could turn on the globsubst and shwordsplit options to get the same behaviour as in Bourne-like shells (those two options are enabled when zsh is invoked as sh for sh compatibility), but I would not recommend that unless you need zsh to interpret code written for another shell (and even in that case, it would make more sense to interpret that code in sh emulation in a local context with emulate -L sh).

Here naming your variable file in

file=*

is misleading if you intend it to be expanded upon expansion¹

filename_pattern=*

would make more sense. If you want a variable holding the name of all the non-hidden files in the current directory, you'd do:

files=(*)

That is, use an array. That would work that same as in bash or ksh93 (where that syntax comes from) mksh or yash, except that zsh doesn't have that other misfeature of the Bourne shell whereby the pattern is left unexpanded when there's no match.


¹Note that * is a perfectly valid name for a file on Unix-like system. I take some comfort in that rm -f -- $file removes the file whose name is stored in $file even if that file is called *.

That would be the first time I see anybody complaining about that (we more often see people complaining about it not doing word splitting upon parameter expansion).

Most people expect

echo $file

to output the content of the $file variable and are annoyed when shells like bash don't (a behaviour inherited from the Bourne shell, unfortunately not fixed by ksh and specified by POSIX for the sh interpreter), and that's causing a lot of bugs and security vulnerabilities and that's why you need to quote all the variables in those shells.

See for instance: Security implications of forgetting to quote a variable in bash/POSIX shells

I see that you're expecting that too as you're writing echo $0 and not echo "$0".

zsh has fixed that. It does neither globbing nor word splitting by default upon parameter expansion. You need to request those explicitly:

  • echo $=file: perform word splitting
  • echo $~file: perform globbing
  • echo $=~file: perform both

Or you could turn on the globsubst and shwordsplit options to get the same behaviour as in Bourne-like shells (those two options are enabled when zsh is invoked as sh for sh compatibility), but I would not recommend that unless you need zsh to interpret code written for another shell (and even in that case, it would make more sense to interpret that code in sh emulation in a local context with emulate -L sh).

Here naming your variable file in

file=*

is misleading if you intend it to be expanded upon expansion¹

filename_pattern=*

would make more sense. If you want a variable holding the name of all the non-hidden files in the current directory, you'd do:

files=(*)

or:

files=(*(N))

for that assignment not to fail if there's no non-hidden file in the current directory.

That is, use an array variable assignment. That would work the same as in bash or ksh93 (where that syntax comes from) mksh or yash, except that zsh doesn't have that other misfeature of the Bourne shell whereby the pattern is left unexpanded when there's no match.


¹Note that * is a perfectly valid name for a file on Unix-like system. I take some comfort in that rm -f -- $file removes the file whose name is stored in $file even if that file is called *.

added 7 characters in body
Source Link
Stéphane Chazelas
  • 584.9k
  • 96
  • 1.1k
  • 1.7k
Loading
added 1 character in body
Source Link
Stéphane Chazelas
  • 584.9k
  • 96
  • 1.1k
  • 1.7k
Loading
deleted 1 character in body
Source Link
Jeff Schaller
  • 68.8k
  • 35
  • 122
  • 265
Loading
added 1 character in body
Source Link
Stéphane Chazelas
  • 584.9k
  • 96
  • 1.1k
  • 1.7k
Loading
added 98 characters in body
Source Link
Stéphane Chazelas
  • 584.9k
  • 96
  • 1.1k
  • 1.7k
Loading
added 825 characters in body
Source Link
Stéphane Chazelas
  • 584.9k
  • 96
  • 1.1k
  • 1.7k
Loading
Source Link
Stéphane Chazelas
  • 584.9k
  • 96
  • 1.1k
  • 1.7k
Loading