https://www.zhihu.com/question/21418449
Mort | Zsh vs. Bash: Incomplete contrast resolution (1) 2014-10-07BdpqlxzWhat's the difference between zsh and bash?
A lot of people have written about "why zsh is better than bash", "Why zsh is better than Shell", the tutorial on how to configure zsh or toss various oh-my-zsh themes is a big basket, but rarely see zsh and bash two shells comparison of specific differences as scripting languages. Well, here is an article, from the perspective of language characteristics of a simple collation of the two minor incompatibilities, for writing portable shell script reference. (just summed up in my own past lessons, so it should be incomplete.) )
Before you begin: Understand the simulation mode of ZSH (emulation mode)
One popular argument is that ZSH is compatible with bash. This is both right and wrong, because zsh itself is not compatible with bash as a scripting language. A script that complies with the Bash specification cannot be guaranteed to be properly executed by the ZSH interpreter. However, the zsh implementation includes a cock bombing simulation mode (emulation mode)that supports simulation of two main Bourne derivative shells (bash, ksh) and C shell (CSH support is incomplete). In Bash's emulation mode, you can use the same syntax and command set as bash for near-full compatibility. In order to activate the emulation of bash, explicit execution is required:
$ emulate bash
is equivalent to:
$ emulate sh
ZSH does not automatically use compatibility mode to interpret scripts based on shebang (such as and) at the beginning of a file, #!/bin/sh
#!/bin/bash
so for zsh to interpret a script that executes a different shell, you still have to manually emulate sh
or emulate ksh
, Tell Zsh which Shell to emulate.
So when will zsh automatically simulate some kind of shell?
For most of today's gnu/linux (except the Debian system) and Mac OS x users, the default /bin/sh
point is bash
:
$ file /bin/sh/bin/sh: symbolic link to `bash‘
Try zsh
to replace bash
the system with a trial /bin/sh
:
# ln -sf /bin/zsh /bin/sh
All bash scripts can still execute correctly because Zsh /bin/sh
can automatically take its corresponding compatibility mode () to execute the command when it is present emulate sh
. Perhaps it is for this reason that GRML directly chooses Zsh as its /bin/sh
, almost perfect compatibility with existing bash scripts.
Irrelevant topic: About
/bin/sh
and shebang portability.
Speaking /bin/sh
, you have to mention, in the context of zsh, refers to the majority of the sh
gnu/linux distribution of the /bin/sh
default point bash
, or at least a subset of bash (if not all GNU Bash's newest features are implemented), Rather than the POSIX shell. As a result, zsh emulate sh
can be used to simulate bash scripts.
As we all know, the default for Debian /bin/sh
is dash (Debian Almquist shell), a purely POSIX shell-compatible implementation that basically doesn't have any of the advanced features you want in bash and ksh. "If you're using a #!/bin/sh
non-POSIX shell in a script, it means that your script is wrong and it's not about our distribution." "Debian developers are declaring the default as a /bin/sh
dash
result of some script errors," he said. of course, it is important that we continue to pretend to be compatible with the POSIX shell standard, even though we are now using a more advanced shell.
Because of the presence of non-GNU Unix, and Debian gnu/linux distributions like this, you cannot assume that the system is /bin/sh
always GNU bash, nor should it be #!/bin/sh
used as a shebang for a Bash script (-- Unless you are willing to give up the advanced features of your shell, write scripts that are compatible with POSIX shell only. If you want this script to be easily ported, you should specify the specific shell interpreter that it relies on:
#!/usr/bin/env bash
This allows the system to always use the correct shell to run the script.
(Of course, explicitly invoking the bash
command to execute the script, shebang how to write it doesn't matter.)
echo
Command/String escape
zsh than Bash, perhaps the most noticeable difference is that The echo
and is built-in commands in Zsh printf
.
$ which echoecho: shell built-in command$ which printfprintf: shell built-in command
The echo
and printf
same built-in commands in Bash are:
$ type echoecho is a shell builtin$ type printfecho is a shell builtin
Thanks to the reader, it is not possible in bash which
to determine whether a command is an external command, because it which
is not itself a built-in command in Bash . which
in Zsh is a built-in command.
The zsh built-in commands are incompatible with the echo
commands we used to use in GNU Bash echo
.
First, take a look at bash:
$ echo $ echo \\\\
We know that because this is passed to echo
just a string (which allows the use of backslashes to \
escape), it is equivalent to not quote with double quotes. Bash outputs the results we expected: every two consecutive \
escapes into one \
character output, and eventually 2 to 1, and 4 to 2. There is nothing to be surprised at.
Can you guess the results of Zsh's output?
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
$ echo $ echo \\\
(゜д゜*)
Explain later.
We also know that to avoid a string being escaped by backslashes, you can put it in single quotes. As we clearly saw in bash, all backslashes are output as-is:
$ echo ‘\\‘$ echo ‘\\\\‘\\\
Once again, can you guess the results of Zsh's output?
↓
↓
↓
↓
↓
↓
↓
↓
↓
↓
$ echo ‘\\‘$ echo ‘\\\\‘\
(((((((((((((((((゜д゜*))))))))
The explanation is this: in the case of the former without quotation marks (or double quotation marks), the string passed to the internal command is first escaped, and the inside is escaped echo
echo \\
\\
\
, and echo \\\\
\\\\
\\
the in is escaped. Then, in echo
this internal command output to the terminal, it will also have to escape this thing again, a separate can not \
be escaped, so it is still as \
output, continuous is \\
escaped \
, so the output is \
. So, echo \\
and echo \\\\
the output is the same, both \
.
To make echo
the output in the zsh not be escaped, you need to explicitly indicate the -E
option:
$ echo -E $ echo -E \\\\
So, we also know how to get exactly the same output as the original string in the latter case of a single quote:
$ echo -E ‘\\‘$ echo -E ‘\\\\‘\\\
The default of bash echo
is not to escape the output, to escape the effect, you need to explicitly specify an -e
option. The incompatibility of command usage in bash and zsh is echo
shown here.
Automatic hyphenation of variables (word splitting)
In bash, you can output a string by invoking an external command echo
:
echo $text
We know that bash will hyphenate the string passed to the command (based on a space or line break), and then pass it as multiple arguments echo
. Of course, the newline as a delimiter is erased at the end of the output. The better habit, then, is to put the variable name in double quotes and pass it as a string so that the line breaks in the text are preserved and exported as is.
echo "$text"
In zsh, you don't need to use double quotes to tell the interpreter " $text
is a string." The interpreter does not convert it to a blank or \n
delimited list of arguments or anything else. So, without trick in bash, echo $text
you can keep line breaks straight. However, as we said in the previous section, we need an extra work to ensure that the output is the original text that is not escaped, and that is the -E
option:
echo -E $text
From here we see that variables in zsh are not automatically cut into words and then in the form of multiple parameters when passed to the command. It is still kept as a quantity . This is an important incompatibility with the traditional Bourne-derived shell (ksh, bash). This is a feature of zsh, not a bug.
Wildcard expansion (globbing)
Wildcard expansion (globbing) may be one of the most practical features of the Unix shell. It is quite limited in function compared to regular expressions, but it does satisfy most of the time: matching files based on a fixed prefix or suffix. The need for more complex patterns is actually rare, at least in file naming and lookups.
How does bash and zsh handle the spread of wildcard characters differently? For example, if we want to enumerate all the files in the current directory .markdown
, there is actually no such file. In zsh: (note that the built-in is used here echo
because we don't want to use External system commands for the time being)
$ echo *.markdownzsh: no matches found: *.markdown
In bash:
$ echo *.markdown*.markdown
Zsh an error due to a wildcard expansion failure, and bash will discard it as a wildcard when it fails to expand, directly returning it as a literal character. It seems that Zsh's approach is more elegant, because you can know that the wildcard is really not expandable, and in bash it's hard to know whether there is a file that doesn't exist or a file named ‘*.markdown‘
.
The next step is the less harmonious aspect.
In the zsh, with the ls
view of course or error:
$ ls *.markdownzsh: no matches found: *.markdown
Bash, this time the call ls
will also error. Because the current directory does not have .markdown
a suffix file, the wildcard expansion fails to become literal ‘*.markdown‘
, the file will not exist naturally, so the external command ls
error:
$ ls *.markdownls: cannot access *.markdown: No such file or directory
The same mistake, where is the difference? For zsh, this is a language-level error; For bash, this is an external command execution error. This difference is important because it means that the latter can be easily caught, while the former cannot.
Imagine a common command-programming language, Java or Python. You can use Try...catch or a similar language structure to capture runtime exceptions and gracefully handle unpredictable errors. The shell certainly does not have a generic exception mechanism, but you can simulate capturing runtime errors by detecting the return value of a command. For example, you can do this in bash:
$ if ls *.markdown &>/dev/null; then :; else echo $?; fi2
Therefore, in the case of a wildcard expansion failure, we can easily redirect the error output of the external command to /dev/null
, and then perform subsequent operations based on the error code that is returned.
In zsh, however, the error output from the ZSH interpreter itself cannot be redirected:
$ if ls *.markdown &>/dev/null; then :; else echo $?; fizsh: no matches found: *.markdown1
Most of the time, we don't want to see these ugly, redundant error outputs, and we expect the program to fully capture these errors, and then do what it's doing. But this may be a normal behavior. The reason is that in the programming language, syntax error is generally not easy for users to catch at runtime, this error will be directly interpreted by the interpreter to complete. Unless, of course, unless we use the evil eval
.
$ if eval "ls *.markdown" &>/dev/null; then :; else echo $?; fi1
Eval is evil. But there seems to be no better way to catch such a mistake in zsh. The reason to do this is that thewildcard expansion failure in ZSH is a syntax error. And in bash, it's not.
For these reasons, relying on the wildcard match failure in bash to directly "*"
pass as literal to the command is not working correctly in zsh. For example, in bash you can: (although it can be used in most cases, it is not scientific to quote without quotation marks)
$ find /usr/share/git -name *.el
Because the zsh does not automatically take the literal as the glob extension fails "*"
, but the direct error terminates the operation, so in the zsh you must "*.el"
enclose the quotation mark to avoid this kind of extension:
$ find /usr/share/git -name "*.el"
string comparison
Determine if two strings are equal in bash:
[ "$foo" = "$bar" ]
or equivalent (more common comparison operators in modern programming languages ==
):
[ "$foo" == "$bar" ]
Note that there must be a space around the equals sign, and the variable name must be enclosed in double quotes. (written by the shell knows the importance of these rules)
In the syntax of conditional judgment, zsh is basically the same as bash, with little improvement. In addition to its interpreter thinking too much, so careless to take it as ==
a other thing:
$ [ foo == bar ]; echo $?zsh: = not found
To use our favorite ==
, only put it in quotation marks to protect it, do not let the interpreter do redundant parsing:
$ [ foo "==" bar ]; echo $?1
So, in order to reduce the number of characters, or honestly use more convenient =
bar.
Array
Also use a simple example to illustrate. Bash:
array=(alpha bravo charlie delta)echo $arrayecho ${array[*]}echo ${#array[*]}for ((i=0; i < ${#array[*]}; i++)); do echo ${array[$i]}done
Output:
alphaalpha bravo charlie delta4alphabravocharliedelta
It's easy to see that the array subscript forbash starts at 0 . $array
is actually the value of the first element of the array, i.e. ${array[0]}
(these behaviors are somewhat like C). To get the entire array of values, you must use ${array[*]}
or ${array[@]}
, therefore, get the length of the array to use ${#array[*]}
. In bash, you must remember to add curly braces to the entire array name along with the subscript when accessing the array elements, for example, ${array[*]}
not to write $array[*]
, otherwise the interpreter would first treat it $array
as a variable.
Let's look at this section of zsh:
array=(alpha bravo charlie delta)echo $arrayecho $array[*]echo $#arrayfor ((i=1; i <= $#array[*]; i++)); do echo $array[$i]done
Output:
alpha bravo charlie deltaalpha bravo charlie delta4alphabravocharliedelta
In Zsh, $array
as in $array[*]
, it can be used to get the value of the entire array. Therefore, the length of the array can be obtained directly $#array
.
The default array subscript for zsh starts at 1 instead of 0 , which is more like the C shell. (although it has been impossible to understand why a shell named C uses 1 as an array subscript to start this wonderful setting)
Finally, ZSH does not need to use curly braces to access the array elements, so the required curly braces in Bash are omitted.
Associative arrays
Support for similar awk associative arrays is provided in both Bash 4.0+ and zsh.
declare -A arrayarray[mort]=foo
As with normal arrays, in bash, you must explicitly access an array element with curly braces:
echo ${array[mort]}
In zsh, however, there is no need:
echo $array[mort]
Here, we notice that Zsh has an unusual feature: support for more complex globbing with square brackets, which array[mort]
in fact creates two semantics: what is the array
element value of this associative array to mort
key? Or does the wildcard expand to match the file name at the beginning of the current directory with a,, "array"
"m"
"o"
, "r"
or "t"
any character?
In the array[mort]=
case of starting as a command, there is no ambiguity, which is an assignment operation on an associative array. In the $
case above, ZSH will automatically recognize the value of the $array[mort]
associative array, which is not too much of a problem. The problem is that it exists in the middle of the command, but not with $
the situation, such as:
read -r -d ‘‘ array[mort] << ‘EOF‘hello worldEOF
Our intention is to assign this heredoc to the array[mort]
array element. In bash, this is perfectly legal. However, in zsh, the interpreter will first attempt to "array[mort]"
glob the pattern, and if there are no files in the current directory that match that pattern, it will of course report a syntax error:
zsh: no matches found: array[mort]
This is a silly thing, in order for this script to be executed correctly by the ZSH interpreter, we need to put it array[mort]
in quotation marks to prevent it from being expanded:
read -r -d ‘‘ ‘array[mort]‘ << ‘EOF‘hello worldEOF
This is zsh the inconvenience of extending some powerful functionality (or the security breach of existing scripting compatibility, or the pitfalls that makes the interpreter confusing).
By the way, rails programmers who build projects with rake know that there are times when you need to pass a parameter value under the command line by square brackets rake
, such as:
$ rake seeder:seed[100]
Zsh the other side of the bracket is really inconvenient to expand the features. If you do not want to enclose the argument in single quotation marks each time, you can completely prohibit zsh glob extension to the parameters following the command: ( ~/.zshrc
)
alias rake="noglob rake"
Well, for the rake
command, the glob extension is basically useless. You can turn it off.
Semicolons and empty statements
Although a bit boring, but still want to mention:bash is not allowed to use empty statements in the statement block , the minimized statement is a NOOP command ( :
), and zsh allows empty statements .
When you start to write bash, you never know when to add a semicolon or not. Like what
if [ 1 ]then :fi
If you put it in one line, it should be
if [ 1 ]; then :; fi
then
The back is not able to answer the semicolon, if written
if [ 1 ]; then; :; fi
You will get an error:
bash: syntax error near unexpected token `;‘
The explanation is: then
represents the beginning of a code snippet, the end of which fi
must be several lines of command, or ;
multiple commands placed in the same line, ending with a semicolon. We know that in a traditional shell, the semicolon itself is not a command, and an empty string is not a command, so the then
semicolon immediately following it brings a syntax error. (sometimes the so-called explanation for a "language feature" is just to hide the designer's mistake at the beginning, so stop there)
In Zsh, both of these are legal. Because it allows empty commands that contain only one semicolon.
$ ;
Of course, because the semicolon is just a statement delimiter, it is not possible. This notation is valid in zsh: ( then
the statement block is empty)
if [ 1 ]; then fi
Second bomb
Actually, it's just digging a hole first. I do not know whether there is no time to write, for the record.
Zsh vs. Bash: Incomplete contrast resolution (2)
- aliases, function definitions, and scopes
- Co-process (coprocess)
- redirect
- Signals and Traps (trap)
Comparison of ZSH and bash on Linux servers
Administrators who use the default instruction column mode (bash shell) may want to take a closer look at Zshell or zsh. The zsh has gained attention in the Linux community because it is similar in bash and has enhanced functionality. So what's the difference between zsh? This article lists the comparison of the data forms of zsh and bash on Linux servers.
-
Mark Source: TechTarget China |
2011-06-13 14:03
-
Mobile collection Sharing
Administrators who use the default instruction column mode (bash shell) may want to take a closer look at Zshell or zsh. The zsh has gained attention in the Linux community because it is similar in bash and has enhanced functionality.
So what's the difference between zsh? First, zsh is similar to bash in both sense and function. But some enhancements make zsh an interesting choice. Here is a comparison of the data forms of zsh and bash on a Linux server:
ZSH Enhancements: Label completion and spelling bug fixes
Administrators who have used bash tags will find the added functionality in zsh impressive. These features include an existing AutoComplete command option in the menu, which can be scrolled by using the arrow keys. For example, type the following command to provide a list of possible command line tags:
$ ls-
Or
$ RM-
Select the specific program that you want to cancel, and the list of programs is available with the Cancel command.
Another feature is in the built-in page program, which provides shortcuts to the less command. To access it, enter:
$<filename
This is the same as running the less file name on the command line.
For clumsy typists, the spelling error correction feature is available. For example, if you enter an error command, ZSH will prompt for a fix:
$ lls
Zsh: Would you like to modify ' lls ' to ' ls ' [nyae]?
To modify it, enter Y, the command is corrected to LS, and the command is ready to run.
Other options are also useful. Enter N to reject the command fixup, enter a interrupt command, and enter E to jump to the command line for editing. This auto-correction feature can also be used for command line tags and file names, including the ability to modify secret transactions of invalid Git branch names.
Getting Started with zsh
To get started quickly with Zsh, the Zsh themes, features, and tools collected by Robby Russell are prepackaged to "Oh My Zsh".
$ wget--no-check-certificate Https://github.com/robbyrussell/oh-my-zsh/raw/master/tools/install.sh-O-| Sh
Manual ZSH Installation instructions are also available, requiring the user to clone the git repo and copy it in the. ZSHRC Draft template.
The "Oh My Zsh" Knowledge Base contains a collection of topics and features for building and changing existing Zsh environments. It can also be used with the unload script to simplify the removal:
$ uninstall_oh_my_zsh
There are also some good documents and zsh reference cards that are supplied with the zsh shell. Online resources on web sites such as GitHub are examples of. zshrc files, which are equivalent to the. bashrc files in version zsh, which also provide examples of how to customize zsh or demonstrate cool techniques for enforcing command-line experience.
Some of the zsh features can be used with bash, but settings and configurations are more complex on bash, which also explains why people have multiple pages. bashrc files. If it is the shell's height user, zsh will be the choice to attract you to replace bash. It's fast and easy to use, and some of its important features make interacting with the shell even more interesting.
Original:http://www.searchsv.com.cn/showcontent_49287.htm
Zsh vs. bash is not completely contrasted, Zsh is a more powerful shell that becomes the "ultimate"