To switch from bash to zsh, you need to know the basic differences between them - without this, it will be difficult to initialize zsh to ~/.zshrc
.
I did not find a brief description of these differences when I switched myself, and I had to spend a lot of time reading the zsh documentation. I hope this article will make it easier for you to go to zsh.
For a start, is it worth spending your time and attention on the transition? To learn another sh dialect, less common than POSIX sh or bash, to re-engage in setting up the working environment ...
In my opinion, if you spend a lot of time in the console, you like Vim or Emacs and you have already spent a lot of time setting them up for yourself - definitely worth it! Zsh is very similar in spirit to them: this is a very complex and flexible program, whose capabilities are completely unknown to most, but after spending some time setting it up you can get a very comfortable working environment for you .
As for the study of the sh dialect ... the benefits of this are probably very few, but the minimum described in this article should be enough to set up zsh, and no one offers you to write new scripts in the zsh dialect. In general, this is no different from the need to minimally know VimL or Emacs Lisp exclusively for configuring Vim / Emacs.
In the internet a bunch of articles and presentations describing specific features zsh, greatly simplified someone's life. I will not list them, because everyone needs different features, and in zsh there are options for every taste. Instead, I will describe the key features of zsh that allowed these features to be implemented:
<Tab>
in different places of the command line, different things will be added: command names, their parameters, files, user and server names, process numbers, variable names, array indices and hash keys, zsh syntax elements , names of colors and fonts, network interfaces, system packages ... in short, in general, everything that can be autocompleted. And it can be monitored in detail, up to a change in the auto-completion logic for a specific context of a particular command.Once again I will clarify that I will describe exactly the differences from bash, and not the full set of zsh features. Most of the functionality you are familiar with works in zsh in the same way as in bash. But there are often zsh-specific ways to do about the same thing. This is due to the fact that zsh pays a lot of attention to compatibility with other shells, so in zsh plus their features they dragged a lot of other shells - and as a result received several alternative ways of doing the same thing.
$@
, $1
, ...).${(kv@)some_hash}
. For templates, they can be at the beginning or middle: *CaseImportant(#i)CaseIgnored*.txt
.*(/^F)
.$PWD:h:t
, ${some_param:h:t}
. For templates, are specified before the closing parenthesis of qualifiers: *(:e)
.Many built-in commands display the current state when they are run without arguments (plus they often have an argument that draws output in the style of zsh commands, which is quite convenient).
# setopt # setopt KSH_OPTION_PRINT; setopt # bindkey # , zsh for m in $(bindkey -l); bindkey -M $m -L # (- ) zstyle zstyle -L # ( ), zsh alias -L # , zsh alias -s -L # () typeset # (), zsh typeset -p
This is not a complete list, but for most tasks in the process of (analyzing) setting up zsh it should be enough.
It may also be useful to run zsh -f
- this starts zsh in the default state (without executing any startup scripts except /etc/zshenv
, which most systems don’t have).
setopt
with the prefix "no" and unsetopt
without "no" (as well as vice versa!) Do the same thing.setopt
output uses small letters without underscores, the documentation uses large letters with underscores. This creates some inconvenience - when searching in the documentation you need to guess where to insert underscores to find the necessary option.emulate
command allows you to set a group of options in bulk to the state of compatibility with sh, ksh, csh or the default state for zsh. Many functions in zsh begin with the emulate -L zsh
command, which allows the key options to be set to the default for zsh for the duration of the function — without this, most non-trivial functions may break due to the options set by the user (for example, there is an option that controls how Arrays are indexed - from 1 or from 0). # setopt nonumericglobsort setopt NO_numericglobsort setopt NO_NUMERIC_GLOB_SORT setopt _N_O_numERICglob_SORT_ unsetopt NUMERIC_GLOB_SORT unsetopt numericglobsort
At the beginning of using zsh, for more familiar work after bash, I would recommend the following options:
# fd unsetopt MULTIOS # ~… file completion = setopt MAGIC_EQUAL_SUBST # escape sequence echo -e setopt BSD_ECHO # setopt INTERACTIVE_COMMENTS # $(cmd) $PS1 etc. setopt PROMPT_SUBST
There is also the SH_WORD_SPLIT
option, and formally, for the usual work after bash, it must also be enabled, but I would not recommend it: the behavior of zsh without this option is more convenient and logical, it is better to get used to it. It is responsible for how cmd $PARAM
will work if the value of $PARAM
is a string containing spaces: in bash, cmd
will get several arguments, and in zsh it will take one (as if they called cmd "$PARAM"
). And if $PARAM
is an array, then zsh will give cmd
one argument for each non-empty element of the array (even if these elements contain spaces).
(Basically, this article describes the behavior of zsh with default options, otherwise every second sentence would have to be clarified in the style of "but with all such options, it all works differently.")
$
letters, and for arrays (ordinary and associative) - $
.typeset -U
you can declare an array with unique elements (attempts to add already existing elements will be ignored).typeset -T
you can associate an array with a scalar in the $PATH
format. Several of these related parameters have already been created: $PATH
and $path
, $FPATH
and $fpath
, $MANPATH
and $manpath
, $CDPATH
and $cdpath
. For related parameters, it does not matter which of them we change - both change at once. Therefore, in zsh, with such parameters almost always work through arrays ( $path
, $fpath
, ...) - this is much more convenient.$PS1
, $PROMPT
and $prompt
(although, they are more likely just synonyms for one parameter).*([2,-2])
.**/
- matches the subdirectory of any nesting level, including the absence of a subdirectory<1-2>
- matches the number in the specified range in the file name, and the beginning and end of the range can be omitted(1|2)
is an alternative (also - grouping brackets when using the EXTENDED_GLOB
option)EXTENDED_GLOB
option, you can optionally use #
(repeat the previous element), ~
and ^
(exclusion from a match) in the templates # , # 5 example, # .txt ls -l **/*(<5->|example)*.txt
Only templates have qualifiers, they allow you to specify additional file selection criteria: by type (file / directory / symlink / etc.), Rights, time (changes / etc.), Size ... You can sort and index selected files. It is possible to include for this particular template a match of the initial *
with names beginning with a dot. You can enable the removal of this template from the command line arguments if it does not match any files.
# 5- , # "a", # ls -ld *a*(D/om[1,5])
If you turn on the EXTENDED_GLOB
option, you can use flags in templates: for files, case-sensitivity management is of interest, and if there is a match with the parameter / line, there are other useful flags.
# ls -ld .[cC][oO][nN][fF][iI][gG]* setopt extendedglob; ls -ld .(#i)Config*
There are much more flags available for parameters: outputting all (including empty) array elements even in quotes, performing join or split on a given substring, outputting only keys and / or associative array values, screening with different types of quotes and inverse operation, etc.
# echo ${(k)some_hash} # $PATH ":", # echo ${(s<:>qq)PATH}
Both for templates and for parameters, modifiers can be used: deleting the last element of the path, deleting all elements of the path except the last, removing / leaving the extension, escaping and inverse operation, searching and replacing substrings, etc.
# ( # , ) echo $PWD:h:t # ( ) , # "fil" "FIL" ( ) echo **/*(@:t:s/fil/FIL/)
In addition to the traditional way to load code via source /path/to/file.sh
or . /path/to/file.sh
. /path/to/file.sh
in zsh autoloading code is actively used at the time of the first function call.
To search for a file with the desired function, $FPATH
is used - a variable similar in format to $PATH
, containing a list of directories in which a file with the same name as the function being loaded is searched.
When autoload
called autoload
no files from the disk are read, and their presence is not even checked - all this will happen when the function is first called. It is almost always necessary to autoload
arguments -U
to the autoload
(cancels the effect of the current alias for the uploaded file, because alias often configured by the user can disrupt third-party functions) and -z
(optional clarification that the uploaded file is in zsh format, but safer than always ask).
fpath=(~/my-zsh-functions $fpath) autoload -Uz fn fn
The contents of the ~/my-zsh-functions/fn
file can be in one of these three formats:
# , - : echo " fn"
# : fn() { echo " fn" }
# , fn: fn() { fn2 } fn2() { echo " fn" } echo " fn" # fn: fn "$@" echo " fn"
When you first run zsh, it often turns out that some of the buttons like the F1 / Backspace / Delete / cursor work incorrectly. This is due to the fact that the vast majority of console applications use readline and the correct configuration of these buttons is read from /etc/inputrc
and ~/.inputrc
, and zsh does not.
The problem is solved in the forehead - you need to see which escape sequences issue the necessary buttons in your terminal and specify the necessary handlers for these escape sequences in ~/.zshrc
. Like that:
bindkey '^[[A' up-line-or-history # Up bindkey '^[[B' down-line-or-history # Down # ..
You can watch the sequences issued by the buttons by running cat >/dev/null
and pressing Ctrl-V
in front of the desired button. (And yet, yes, doing this in 2017 I felt a bit strange ...) But with zsh, there is a utility utility, zkbd
, that automates this process. To do this, you must connect it to ~/.zshrc
, after which you will have an associative $key
array containing the necessary escape sequences:
autoload -Uz zkbd [[ ! -f ~/.zkbd/$TERM-${${DISPLAY:t}:-$VENDOR-$OSTYPE} ]] && zkbd source ~/.zkbd/$TERM-${${DISPLAY:t}:-$VENDOR-$OSTYPE} [[ -n $key[Up] ]] && bindkey -- $key[Up] up-line-or-history [[ -n $key[Down] ]] && bindkey -- $key[Down] down-line-or-history # ..
I do not elaborate in detail which commands (such as up-line-or-history
) which buttons should be assigned because, first, you do not have to assign everything, but only those that do not work out of your box, and second, if you think As for what everyone should do, Home or Backspace all converge, here's a search in the history of Up and Down can be done in quite different ways, and the functions in these cases must also be assigned to these buttons.
(By the way, you can set the Escape character ( ^[
) in the bindkey parameter with a real character, typing it using Ctrl-V
, and two ordinary characters ^[
, and two characters \e
.)
This is a built-in way to use context-sensitive settings. It is in many ways similar to the usual parameters, except for the name and value of the zstyle
parameter, zstyle
allows zstyle
to specify a "context" template. And then get the values related to the current context. This approach is actively used to customize the work of autocompletions, but it can also be used for your scripts.
# my-param=default 3- , # ( # zstyle, ) # % zstyle ':my-app:*:*' my-param default # my-param=val-one , # ( ) "one" % zstyle ':my-app:one:*' my-param val-one # my-param=val-two , # ( ) "two" % zstyle ':my-app:*:two' my-param val-two # my-param result % zstyle -s ':my-app:a:b' my-param result % echo $result default % zstyle -s ':my-app:one:b' my-param result % echo $result val-one % zstyle -s ':my-app:a:two' my-param result % echo $result val-two % zstyle -s ':my-app:one:two' my-param result % echo $result val-one
Part of the additional functionality of zsh is not implemented in regular scripts loaded via autoload -Uz
, but as system libraries *.so
. They are used, for example, to provide access to PCRE regular expressions, math functions, sockets, etc. Such libraries are loaded via zmodload
.
To intercept signals, in addition to the standard trap '…;code;…' INT
you can use functions with special names: TRAPINT() { …;code;… }
.
Many constructions like if
, while
, etc. there is an abbreviated form (an example is above, where the value of all bindkey modes was displayed).
Suddenly, the zsh-specific equivalent of echo
— the print
command — turned out to be quite handy when learning zsh. She knows a lot of things, but from the most useful:
# , print -l $path # , # print -a -C 2 "${(kv@)ZSH_HIGHLIGHT_STYLES}" | sort # %- $PS1 print -P '%Bbold%b %F{red}current%f dir is: %~'
zsh, // Awesome- zsh .
Source: https://habr.com/ru/post/326580/
All Articles