(摘) Zsh开发指南

声明:内容源自网络,版权归原作者所有。若有侵权请在网页聊天中联系我

根据之前学习zsh shell及oh my zsh的安装,学习一下网友提供的文章。

这里也作了一些zsh讲解

内容较多,全是好货,静下心来慢慢看,需要的时候再来查即可。

一、提示符

编辑用户目录下.zshrc文件,添加 export PS1=“my zsh ps1> "

下面是一些常用的转义变量

%T 系统时间时分
%* 系统时间时分秒
%D 系统时间年月日
%@ am/pm 时间
%n 登陆用户名
%B - %b 粗体打印
%U - %u 下划线打印
%S - %s 突出打印
%F - %f 前景色
%K - %k 背景色
%d 当前目录
%M 主机名
%m 截断过的主机名
%l 当前tty
%! 历史记录编号
$# 显示#号或>号

更多的转义变量看这里

颜色

在 .zshrc 中 PROMPT= 前面添加 autoload -U colors && colors 来启用彩色提示符。

通常你需要将这些配置放在 %{ […] %} 里面确保光标不移动。

$fg[color] 会设置文本的颜色

命令 描述
%F{color} […] %f 和前面介绍的 $fg 是一样的,但是更简洁。还可以在 F 前面添加数字。
$fg_no_bold[color] 设置文本为非粗体同时设定文本颜色
$fg_bold[color] 设置文本为粗体同时设定文本颜色
$reset_color 重置文本颜色(改为默认颜色)。不会重置粗体设定。使用 %b 来重置粗体设定。可以使用 %f 来简化配置。
%K{color} […] %k 设置背景颜色。和非粗体文本颜色一样。任何单一数字前缀会设置背景为黑色。
PROMPT="%{$fg[red]%}%n%{$reset_color%}@%{$fg[blue]%}%m %{$fg[yellow]%}%1~ %{$reset_color%}%#"
RPROMPT="[%{$fg[yellow]%}%?%{$reset_color%}]"

目录栈

可用于目录的快速跳转,在.zshrc中添加

DIRSTACKFILE="$HOME/.cache/zsh/dirs"
if [[ -f $DIRSTACKFILE ]] && [[ $#dirstack -eq 0 ]]; then
  dirstack=( ${(f)"$(< $DIRSTACKFILE)"} )
  [[ -d $dirstack[1] ]] && cd $dirstack[1]
fi
chpwd() {
  print -l $PWD ${(u)dirstack} >$DIRSTACKFILE
}

DIRSTACKSIZE=20

setopt autopushd pushdsilent pushdtohome

## Remove duplicate entries
setopt pushdignoredups

## This reverts the +/- operators.
setopt pushdminus

帮助

autoload -U run-help
alias help=run-help

二、变量和语句

zsh 有 5 种变量:整数、浮点数(bash 不支持)、字符串、数组、哈希表(或者叫关联数组或者字典,本系列文章统一使用哈希表)

变量定义

Zsh 的变量多数情况不需要提前声明或者指定类型,可以直接赋值和使用(但哈希表是一个例外)。

# 等号两端不能有空格
num1=123
num2=123.456
str1=abcde

# 如果字符串中包含空格等特殊字符,需要加引号
str2='abc def'

# 也可以用双引号,但和单引号有区别,比如双引号里可以使用变量,而单引号不可以
str3="abc def $num1"

# 在字符串中可以使用转移字符,单双引号通用
str4="abc\tdef\ng"

# 输出变量,也可以使用 print
echo $str1

# 简单的数值计算
num3=$(($num1 + $num2))
# (( 中的变量名可以不用 $
% num3=$((num1 + num2))

# 2 和 4 都是字符在数组的位置,从 1 开始数,逗号两边不能有空格
echo $str[2,4]

# -1 是最后一个字符
% echo $str[4,-1]	

变量比较

# 比较数值
num=123

# (( )) 用于数值比较等操作,如果为真返回 0,否则返回 1
# && 后边的语句在前边的语句为真时才执行
# 双等号可以替换成单等号,可以根据自己的习惯选用,其他多数地方也是如此
((num == 123)) && echo good

# (( 里边可以使用与(&&)或(||)非(!)操作符,同 c 系列语言
((num == 1 || num == 2)) && echo good

# 比较字符串
# 比较字符串要用 [[,内侧要有空格,字符串最好用引号包含,避免产生语法错误
[[ "$str" == "abc" ]] && echo good

# 可以和空字符串 "" 比较,未定义的字符串和空字符串比较结果为真
# [[ 里也可以用 && || !,但不能随意加小括号,[[ 的用法比 (( 要严格很多
[[ "$str" == "" || "str" == "123" ]] && echo good	

条件语句

if [[ ]] {
} elif {
} else {
}
# elif 也可以写作 else if

注意尽量不要用 [[ ]] 比较数值,因为数值可能会被转化成字符串来比较

# 样例
if [[ "$str" == "name" || "$str" == "value" ]] {
    echo "$str"
}

(( )) 用于比较数值,里边可以调用各种数值相关的函数,格式类似 c 语言,变量前的 $ 可省略。

# 格式
if (( )) {
}

# 样例
if ((num > 3 && num + 3 < 10)) {
    echo $num
}

{ } 用于在当前 shell 运行命令并且判断运行结果。

# 格式
if { } {
}

# 样例
if {grep sd1 /etc/fstab} {
    echo good
}

() 用于在子 shell 运行命令并且判断运行结果,用法和 {} 类似

# 格式
if ( ) {
}

# 混合使用
if [[ ]] && (( )) && { } {
}

循环语句

# 格式
while [[ ]] {
    break/continue
}

# 样例 死循环
 while (( 1 )) {
    echo good
}

# until 和 while 相反,不满足条件时运行
until [[ ]] {
}

# for 循环主要用于枚举,
# 这里的括号是 for 的特有用法,不是在子 shell 执行。
# 括号内是字符串(可放多个,空格隔开)、数组(可放多个)或者哈希表(可放多个,哈希表是枚举值而不是键)。i 是用于枚举内容的变量名,变量名随意。
for i ( ) {
}

# 样例
for i (aa bb cc) {
    echo $i
}

# 枚举当前目录的 txt 文件
for i (*.txt) { 
    echo $i
}

# 枚举数组
array=(aa bb cc)
for i ($array) {
    echo $i
}

# c 风格 for 循环
for (( ; ; )) {
}

# 样例
for ((i=0; i < 10; i++)) {
    echo $i
}

for i ({1..10}) {
    echo $i
}

# repeat 语句用于循环固定次数,n 是一个整数或者内容为整数的变量。
repeat n {
}

# 样例
repeat 5 {
    echo good
}

分支语句

# 格式 + 样例
case i {
    (a)
    echo 1
    ;;

    (b)
    echo 2
    # 继续执行下一个
    ;&

    (c)
    echo 3
    # 继续向下匹配
    ;|

    (c)
    echo 33
    ;;

    (d)
    echo 4
    ;;

    (*)
    echo other
    ;;
}

;; 代表结束 case 语句,;& 代表继续执行紧接着的下一个匹配的语句(不再进行匹配),;| 代表继续往下匹配看是否有满足条件的分支。这个是比较特别的。

用户输入选择语句

select 语句是用于根据用户的选择决定分支的语句,语法和 for 语句差不多,如果不 break,会循环让用户选择。

# 格式
select i ( ) {
}

# 样例
select i (aa bb cc) {
    echo $i
}

将输出 1) aa 2) bb 3) cc ?# 按上边的数字回车来选择。

异常处理语句

# 如果语句1出错,则执行语句2
{
    语句1
} always {
    语句2
}

简化的条件语句

#针对只有一个分支的情况
[[ ]] || {

}

[[ ]] && {

}

三、字符串处理

字符串长度

str=abcde
echo $#str

# 读取函数或文件第一个参数的长度
echo $#1 

字符串拼接

str1=abc
str2=def

str2+=$str1
str3=$str1$str2

字符串切片

str=abcdef
echo $str[2,4]  #bcd
echo $str[2,-1] #bcdef

字符串截断

str=abcdeabcde

# 删除左端匹配到的内容,最小匹配
echo ${str#*b}  #cdeabcde

# 删除右端匹配的内容,最小匹配
echo ${str%d*}  #abcdeabc

# 删除左端匹配到的内容,最大匹配
echo ${str##*b}    #cde

# 删除右端匹配到的内容,最大匹配

echo ${str%%d*}    #abc

字符串查找

str=abcdef

echo $str[(I)cd]  #3

# I是从右往左找,如果找不到则为0
echo $str[(I)cdd]  #0

(( $str[(I)cd] )) && echo good    #good

# i是从左往右找,找不到则返回数组大小+1
echo $str[(i)cd]   #3
echo $str[(i)cdd]  #7

遍历字符

str=abcd
for i ({1..$#str}) {
    echo $str[i]
}

字符串替换

str=abcabc

# 只替换找到的第一个
echo ${str/bc/ef}  #aefabc

# 删除匹配到的第一个
echo ${str/bc}     #aabc

# 替换所有找到的所有
echo ${str//bc/ef}  #aefaef

# 删除匹配到的所有
echo ${str//bc}     #aa

str=abcABCabcABCabc

# 只从字符中开头开始匹配
echo ${str/#abc/123}    #123ABCabcABCabc

# 只从字符串结尾匹配
echo ${str/%abc/123}    #abcABCabcABC123

str=abc

# 如果匹配不到,则输出原字符串
echo ${str:#ab}   #abc

# 加M后效果反转,匹配不到则输出空
echo ${(M)str:#ab}

按位置删除

str=abcdef

# 删除指定位置字符
str[1]=
echo $str   #bcdef

# 删除多个
str[2,4]=   #bf

按位置替换

str=abcdefg

# 一对一替换
str[2]=1          # str=a1cdefg

# 多对多替换
str[2,3]=2345     # str=a2345defg    

判断是否存在

(( $+str )) && echo good    #返回空
str=""
(( $+str )) && echo good    #返回good

匹配判断

str1=abcd
str2=bc

[[ "$str1" == *"$str2"* ]] && echo good    # good

正则表达式匹配

str=abc55def

[[ "$str" =~ "c[0-9]{2}\de" ]] && echo a   # a

大小写转换

str="ABCDE abcde"

echo ${(U)str} --- ${str:u}   #ABCDE ABCDE --- ABCDE ABCDE
echo ${(L)str} --- ${str:l}   #abcde abcde --- abcde abcde
# 首字母大写
echo ${(C)str}  # Abcde Abcde

目录文件名截取

filepath=/a/b/c.x

# :h 取目录名
echo ${filepath:h}    #/a/b

# :t 取文件名
echo ${filepath:t}    #c.x

# :e 取文件扩展名,如果没有则为空
echo ${filepath:e}

字符串分隔

str='aa bb cc dd'
echo ${str[(w)2]}    #bb
echo ${str[(w)3]}    #cc
str='aa--bb--cc'
echo ${str[((ws:--:)3)]}  #指定分隔符

多行字符串

str="line1
> line2"

读取文件内容到字符串

#比用str=$(cat filename)性能好很多
str=$(<filename)
echo "$(<filename)"

#遍历每行
for i (${(f)"$(<filename)"}) {
    echo $i
}

读取文件指定行

#读取第二行
echo ${"$(<test.txt)"[(f)2]}

#输出包含ang的第一行
echo ${"$(<test.txt)"[(fr)*ang*]}

#输出包含pp的第一行,但从左截掉line 4个字符。
echo ${"$(<test.txt>)"[(fr)*pp*]#line}

读取进程输出到字符串

类似于文件,将$(<test.txt)换成$(命令)即可。

四、字符串处理:转义符和格式化输出

\n 换行
\r 回车
\t Tab
\\ \
\` `

可用hexdump命令查看字符的ASCII码值: echo ab= | hexdump -C 将显示abc及换行符的ASCII码

#-r 代表忽略字符串中的转义符
#${((q))str} 为字符串中的特殊符号添加转义符号
print -r ${((q))str}

单引号

#用双引号包含单引号
echo "a'b"
#用转义符
echo a\`b 

双引号

#使用变量
echo "$str"

#运行命令
echo "$(ls)" 

#用``运行命令
echo "`date`"

#使用$(())计算数值
echo "$(( 1+2 ))"

#使用$[]计算数值
echo "$[1+2]"

反引号

反引号是用来运行命令的,返回结果到变量等。反引号的功能和$()功能基本一样,但$()可以嵌套

str=`ls`

print命令用法

-l 分行输出字符串

print -l aa bb

array=(aa bb)
print -l $array
``

-n 不再输出内容的末尾自动添加换行符

-m 用于只输出匹配到的字符串

print -m “aa*” aabb abc aac #aabb aac


-o 字符串升序

-O 字符串降序

-i 对大小写不敏感

-r 不对字符串进行转义

-c 字符串按列输出

-C 按指定列数输出字符串

-D 将符合条件的路径名转化成带~的格式,即相对于HOME目录的路径

-N 将输出的字符串以\x00分隔

-x 将行首的Tab换成空格

-X Tab换成空格,带空格补全

-u 指定fd输出,默认输出到fd 1,即stdout。2是stderr

-v 把输出内容保存到变量

print -v str aa bb cc echo $str


-s/-S 用于把字符串保存到历史记录

-z 把字符串输出到命令行编辑区

-f 按指定格式输出,同printf

-P 输出带颜色和特殊样式的字符串

**printf命令**

相关文章