linuxshell学习笔记(2)

语句

记住了两句话:每个语句后面都得记得打个空格,不然会编译错误!(语法规范问题)

                          赋值时等号两侧不能有空格,比较时等号两侧必须有空格!

条件语句

# 格式
if [[ ]] {
} elif {
} else {
}

注意: elif 不可写作 else if。 

[[ ]] 用于比较字符串、判断文件等,功能比较复杂多样,这里先使用最基础的用法。注意尽量不要用 [[ ]] 比较数值,因为不留神的话,数值会被转化成字符串来比较,没有任何错误提示,但结果可能不符合预期,导致不必要的麻烦。

# 样例
#!/usr/bin/env zsh
read str
if [[ "$str" == "name" || "$str" == "value" ]] {
    echo "$str"
}else{
    echo False
}

输出
1.value
  value
2.suv
  False

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

# 格式
if (( )) {
}
# 样例
#!/usr/bin/env zsh
read num
if ((num > 3 && num + 3 < 10)) {
    echo $num
}

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

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

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

# 格式
if ( ) {
}

 

这几种括号可以一起使用,这样可以同时判断字符串、数值、文件、命令结果等等。最好不要混合使用 &&  ||,会导致可读性变差和容易出错。

# 格式
if [[ ]] && (( )) && { } {
}

循环语句

while

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

和 if 一样,这里的 [[ ]] 可以替换成其他几种括号,功能也是一样的;break 用于结束循环,continue 用于直接进入下一次循环。所有的循环语句中都可以使用 break 和 continue.

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

until 

until 和 while 相反,不满足条件时运行,一旦满足则停止,其他的用法和 while 相同。

# 格式
until [[ ]] {
}

for 

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

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

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

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

输出
aa
bb
cc
aa
be
cf

经典的 c 风格 for 循环。

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

这个样例只是举例,实际上多数情况不需要使用这种 for 循环,可以这样。

# 样例,{1..10} 可以生成一个 1 到 10 的数组
for i ({1..10}) {
    echo $i
}

repeat 语句 

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

# 格式
repeat n {
}
# 样例
repeat 5 {
    echo good
}

输出
good
good
good
good
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
} always {
    语句 2
}

无论语句 1 是否出错,都执行语句 2。

#!/usr/bin/env zsh
read num
{
        if (( num == 3 )) {
                echo right
        }
} always {
        echo false
}

简化的条件语句 

if 语句的简化版,在只有一个分支的情况下更简洁,功能和 if 语句类似,不赘述。

格式:
[[ ]] || {
}

[[ ]] && {
}

最好不要连续混合使用 && ||,比如。

aa && bb || cc && dd

容易导致逻辑错误或者误解,可以用 { } 把语句包含起来。

aa && { bb || { cc && dd } }

比较复杂的判断还是用 if 可读写更好,&& || 通常只适用于简单的场景。 

bc计算

感谢[Linux] Linux下使用bc进行计算公式_bc运算-CSDN博客 与 Linux bc 命令 | 菜鸟教程 (runoob.com)对本人在该部分学习的帮助;

常用的运算:

  • + 加法
  • - 减法
  • * 乘法
  • / 除法
  • ^ 指数
  • % 余数

语法

bc(选项)(参数)
选项值
  • -i:强制进入交互式模式;
  • -l:定义使用的标准数学库
  • ; -w:对POSIX bc的扩展给出警告信息;
  • -q:不打印正常的GNU bc环境信息;
  • -v:显示指令版本信息;
  • -h:显示指令的帮助信息。
参数

文件:指定包含计算任务的文件。

通过管道符

命令解释:


echo命令将双引号内部的计算式作为参数 传给程序bc(类似于管道),然后bc进行计算得到结果后显示输出;

或者可以不使用echo运算符,直接将需要计算的公式字符串作为参数传给程序bc,例如:

bc <<< "1+2"

输出为:

3

使用scale变量设置结果小数点后的位数,例如:

sth@sth-pc:~$ echo "scale=1;3/4" | bc
.7
sth@sth-pc:~$ echo "scale=2;3/4" | bc
.75

三角函数、开方和幂次运算


bc在使用参数-l指定代数运算模式下也支持三角函数、开方、幂次等操作。
但是与matlab等语言不同的是,为了简化代码,bc中三角函数与数学上的函数名字有所不同,具体如下:

s(x) 计算 sin(x),以下x皆为弧度表示
c(x) 计算 cos(x)
a(x) 计算arctangent(x)
l(x) 计算ln(x)
e(x) 计算e的x次方,其中e为自然底数
x^y 计算x的y次方
sqrt(x) 计算根号下x

注意,进行三角函数、开方,幂次等代数运算时,一定要加上参数-l,表示进行代数运算,不然无法使用内置的三角函数、开方等函数。

进制转换

#!/bin/bash

abc=192 
echo "obase=2;$abc" | bc

执行结果为:11000000,这是用bc将十进制转换成二进制。

#!/bin/bash 

abc=11000000 
echo "obase=10;ibase=2;$abc" | bc

执行结果为:192,这是用bc将二进制转换为十进制。

计算平方和平方根:

$ echo "10^10" | bc 
10000000000
$ echo "sqrt(100)" | bc
10

编程习惯 

推荐给所有变量加上花括号,这是个好的编程习惯。

已定义的变量,可以被重新定义,如:

实例

your_name="tom"
echo $your_name
your_name="alibaba"
echo $your_name

这样写是合法的,但注意,第二次赋值的时候不能写$your_name="alibaba",使用变量的时候才加美元符($)

删除变量

使用 unset 命令可以删除变量。语法:

unset variable_name

变量被删除后不能再次使用。unset 命令不能删除只读变量。

特殊变量 

有一些特殊变量在 Shell 中具有特殊含义,例如 

$0 表示脚本的名称,$1, $2, 等表示脚本的参数。

$#表示传递给脚本的参数数量,$? 表示上一个命令的退出状态等。

 echo命令

不加引号:字符串原样输出,变量会被替换。(根双引号一样,唯一的不同在于 \ 和 空格)

单引号:引号里面的内容会原封不动的显示出来(很简单,不做解释)

双引号:里面的特殊符号会被解析,变量也会被替换(\ 符号、空格会被解析)

反引号:用于显示命令执行结果

单双引号的优缺点

 

单引号字符串的限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字符串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。

双引号的优点:

  • 双引号里可以有变量
  • 双引号里可以出现转义字符

 

字符串操作 

 这部分感谢 Linux shell字符串截取、替换、删除以及trim_shell trim-CSDN博客

拼接字符串

实例

your_name="runoob"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting  $greeting_1

# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2  $greeting_3

输出结果为:

hello, runoob ! hello, runoob !
hello, runoob ! hello, ${your_name} !

可以明显看出,不加单双引号,不会输出变量,而是会原模原样输出!

用+号符

% str1=abc
% str2=def

% str2+=$str1
% echo $str2
defabc

将两个变量拼接 

s1=Hi,
s2=Jack
s=${s1}${s2}    # 可以写作$s1$s2,但最好形成好的编程习惯
echo "$s"    # 必须是双引号

获取字符串长度

实例

string="abcd"
echo ${#string}   # 输出 4

变量为字符串时,bash中${#string} 等价于 ${#string[0]},zsh中${#string} 等价于 ${#string[1]}:

实例

string="abcd"
echo ${#string[0]}   # 输出 4

截取子字符串

% str=abcdeabcde

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

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

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

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

 总结:从左至右为#,*截取字符串前面,第一个则为#,最后一个则为##;从右至左为%,第一个则为%,最后一个则为%%,*截取字符串后面。

从位置1截取到末尾

word=abcd-//master-01://httpab
echo ${word:1} 
# 输出:bcd-//master-01://httpab


从位置-1截取到末尾,就是截取最后一个

word=abcd-//master-01://httpab
echo ${word:(-1)} 
# 输出:b

注意无论是bash还是zsh,第一个字符的索引值均为 0。

查找子字符串

查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):

实例

string="runoob is a great site"
echo `expr index "$string" io`  # 输出 4

注意: 以上脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。

替换字符串

从左到右,匹配第一个,替换//为cd

#![usr/bin/env zsh
word=abcdp//hushush//httpab
echo ${word/\/\//cd}

输出:abcdpcdhushush//httpab
注意:\相当于转义符;
将所有匹配的//替换为cd

#![usr/bin/env zsh
word=abcdp//hushush//httpab
echo ${word//\/\//cd}

输出为:abcdpcdhushushcdhttpab

按内容替换和删除字符

% str=abcabc

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

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

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

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


% str=abcABCabcABCabc

# /# 只从字符串开头开始匹配,${str/#abc} 也同理
% echo ${str/#abc/123}
123ABCabcABCabc

# /% 只从字符串结尾开始匹配,echo ${str/%abc} 也同理
% echo ${str/%abc/123}
abcABCabcABC123


% str=abc

总结:/:只替换或者删除找到的第一个;//: 删除或者替换所有匹配到的;

        /#:只从字符串开头开始匹配,找到第一个;

        /%:只从字符串结尾开始匹配,找到第一个;

# 如果匹配到了则输出空字符串
% echo ${str:#ab*}

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

# 加 (M) 后效果反转
% echo ${(M)str:#ab}

按位置删除字符

%str=abcdef

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

# 可以删除多个
% str[2,4]=
% echo $str
bf

跟C语言一样,对应位置写入空; 

按位置替换字符

% str=abcdefg

# 一对一地替换
% str[2]=1
% echo $str
a1cdefg

# 可以多对多(也包括一对多和多对一)地替换字符,两边的字符数量不需要一致。
# 把第二、三个字符替换成 2345
% str[2,3]=2345
% echo $str
a2345defg

遍历字符

% str=abcd

% for i ({1..$#str}) {
>    echo $str[i]
>}
a
b
c
d

这个就是常见的,用for循环遍历一个数组;

字符串判断

判断字符串变量是否存在

如果用 [[ "$strxx" == "" ]] ,那无法区分变量是没有定义还是内容为空,在某些情况是需要区分二者的

% (($+strxx)) && echo good

% strxx=""
% (($+strxx)) && echo good
good

(($+var)) 的用法也可以用来判断其他类型的变量,如果变量存在则返回真(0),否则返回假(1)。

字符串匹配判断

判断是否包含字符串。

% str1=abcd
% str2=bc

% [[ $str1 == *$str2* ]] && echo good
good

正则表达式匹配。(还不太清楚)

% str=abc55def

# 少量字符串的话,尽量不要用 grep
# 本文不讲正则表达式格式相关内容
# 另外 zsh 有专门的正则表达式模块
% [[ $str =~ "c[0-9]{2}\de" ]] && echo a
a

 

大小写转换

% str="ABCDE abcde"

# 转成大写,(U) 和 :u 两种用法效果一样
% echo ${(U)str} --- ${str:u}
ABCDE ABCDE --- ABCDE ABCDE

# 转成小写,(L) 和 :l 两种用法效果一样
% echo ${(L)str} --- ${str:l}
abcde abcde --- abcde abcde

# 转成首字母大写
% echo ${(C)str}
Abcde Abcde

 总结:转成大写,(U) 和 :u 两种用法效果一样;转成小写,(L) 和 :l 两种用法效果一样;转成首字母大写,(C)。

目录文件名截取

% filepath=/a/b/c.x

# :h 是取目录名,即最后一个 / 之前的部分,如果没有 / 则为 .
% echo ${filepath:h}
/a/b

# :t 是取文件名,即最后一个 / 之后的部分,如果没有 / 则为字符串本身
% echo ${filepath:t}
c.x

# :e 是取文件扩展名,即文件名中最后一个点之后的部分,如果没有点则为空
% echo ${filepath:e}
x

# :r 是去掉末尾扩展名的路径
% echo ${filepath:r}
/a/b/c

 总结::h 是取目录名,即最后一个 / 之前的部分,如果没有 / 则为 .

:t 是取文件名,即最后一个 / 之后的部分,如果没有 / 则为字符串本身

:e 是取文件扩展名,即文件名中最后一个点之后的部分,如果没有点则为空

:r 是去掉末尾扩展名的路径

字符串分隔

# 使用空格作为分隔符,多个空格也只算一个分隔符
% str='aa bb cc dd'
% echo ${str[(w)2]}
bb
% echo ${str[(w)3]}
cc

# 指定分隔符
% str='aa--bb--cc'
# 如果分隔符是 : 就用别的字符作为左右界,比如 ws.:.
% echo ${str[(ws:--:)3]}
cc

注意:使用空格作为分隔符,多个空格也只算一个分隔符;数组的索引从1开始;

# 或者先转换成数组
% str="1:2::4"
% str_array=(${(s/:/)str})
% echo $str_array
1 2 4
% echo $str_array[2]
2
% echo $str_array[3]   # 124
4

# 保留其中的空字符串
% str_array=("${(@s/:/)str}")
% echo $str_array[3]

% echo $str_array[4]   # 12 4
4

注意:(@s/:/)与(s/:/)的区别 

多行字符串

字符串定义可以跨行。

% str="line1
> line2"
% echo $str
line1
line2

读取文件内容到字符串

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

# 比用 cat filename 性能好很多,引号不能省略
echo "$(<filename)"

# 遍历每行,引号不能省略
for i (${(f)"$(<filename)"}) {
    echo $i
}

读取文件指定行。

读取进程输出到字符串

读进程输出和读文件类似。

上边字符串相关的处理,直接把 $(<test.txt) 换成 $(命令) 即可。如果一定需要一个文件名,可以这样。

# 返回 fd 路径,优先使用,但某些场景会出错
% wc -l <(ps)
4 /proc/self/fd/11

# 临时文件,会自动删除,适合上边用法出错的情况
% wc -l =(ps)
3 /tmp/zshMWDpqD

 

 

  • 27
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值