Shell

🏠 首页 / Linux / shell 基础

shell 基础 #

shell 注释 #

单行注释:

# 注释内容

多行注释:

:<<EOF
注释内容
注释内容
注释内容
EOF

:<<!
注释内容
注释内容
注释内容
!

:<<'
注释内容
注释内容
注释内容
'

shell 变量 #

定义变量:

my_name="Ding Peng"

使用变量:

$my_name
${my_name}

只读变量:

my_name="Ding Peng"
readonly my_name 

删除变量:

unset my_name

变量类型:

  1. 局部变量:在脚本或命令中定义,仅在当前shell实例有效
  2. 环境变量:所有shell实例有效
  3. shell变量:shell程序设置的特殊变量

shell 字符串 #

单引号与双引号的区别:

  1. 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  2. 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用;
  3. 双引号里可以有变量;
  4. 双引号里可以出现转义字符
my_name="Ding Peng"
hello_string="Hllo,\"$my_name\"!"
echo $hello_string

获取字符串长度:

my_name="dp"
echo ${#my_name} # 输出5

截取字符串:

hello_world="Hello World!"

# 从index 1截取4个字符
echo ${hello_world:1:4}  # 输出ello

shell 数组 #

只有以为数组,没有多维数组

# 定义数组,空格隔开
names=('Ding Peng' 'Jay Chou' "Lebron James")

# 获取数组元素,根据index获取
echo ${names[1]}

# 获取数组长度
echo ${#names[@]}
echo ${#names[*]}

shell 传参 #

执行shell脚本文件时,传递参数

假如有一个test.sh文件内容如下:

#!/bin/bash

echo "Shell 传递参数实例!";

# 使用$n接收参数
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
chmod +x test.sh
./test.sh 1 2 

第一行命令给test.sh添加可执行权限

第二行命令执行test.sh文件

以上命令将输出:

Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2

其他参数处理:

参数说明
$#传递到脚本的参数个数
$*以一个单字符串显示所有向脚本传递的参数
$$脚本运行的当前进程ID号
$@与$*相同,但是使用时加引号,并在引号中返回每个参数。

shell if 控制语句 #

if 后面需要接者 then

if [ condition-for-test ]
then
  command
  ...
fi

或者,

if [ condition-for-test ]; then
  command
  ...
fi

如:

#!/bin/bash
 
VAR=myvar
if [ $VAR = myvar ]; then
    echo "1: \$VAR is $VAR"   # 1: $VAR is myvar
fi
if [ "$VAR" = myvar ]; then
    echo "2: \$VAR is $VAR"   # 2: $VAR is myvar
fi
if [ $VAR = "myvar" ]; then
    echo "3: \$VAR is $VAR"   # 3: $VAR is myvar
fi
if [ "$VAR" = "myvar" ]; then
    echo "4: \$VAR is $VAR"   # 4: $VAR is myvar
fi

上面,我们在比较时,可以用双引号把变量引用起来。

但要注意单引号的使用。

#!/bin/bash
VAR=myvar
if [ '$VAR' = 'myvar' ]; then
    echo '5a: $VAR is $VAR'
else
    echo "5b: Not equal."
fibas
# Output:
# 5b: Not equal.

上面这个就把 '$VAR' 当一个字符串了。

但如果变量是多个单词,我们就必须用到双引号了,如

#!/bin/bash

# 这样写就有问题
VAR1="my var"
if [ $VAR1 = "my var" ]; then
    echo "\$VAR1 is $VAR1"
fi
# Output
# error [: too many arguments

# 用双引号
if [ "$VAR1" = "my var" ]; then
    echo "\$VAR1 is $VAR1"
fi

总的来说,双引号可以一直加上。

空格问题 #

比较表达式中,如果 = 前后没有空格,那么整个表法式会被认为是一个单词,其判断结果为 True.

#!/bin/bash
 
VAR2=2
#  由于被识别成一个单词, [] 里面为 true
if [ "$VAR2"=1 ]; then
    echo "$VAR2 is 1."
else
    echo "$VAR2 is not 1."
fi
# Output
# 2 is 1.

# 前后加上空格就好了
if [ "$VAR2" = 1 ]; then
    echo "$VAR2 is 1."
else
    echo "$VAR2 is not 1."
fi
# Output
# 2 is not 1.

另外需要注意的是, 在判断中,中括号 [ 和变量之间一定要有一个空格,= 或者 ==。 如果缺少了空格,你可能会到这类似这样的错误:unary operator expected’ or missing]` 。

# 正确, 符号前后有空格
if [ $VAR2 = 1 ]; then
    echo "\$VAR2 is 1."
else
    echo "It's not 1."
fi
# Output
# 2 is 1.

# 错误, 符号前后无空格
if [$VAR2=1]; then
    echo "$VAR2 is 1."
else
    echo "It's not 1."
fi
# Output
# line 3: =1: command not found
# line 5: [=1]: command not found
# It's not 1.

文件测试表达式 #

对文件进行相关测试,判断的表达式如下:

表达式True
file1 -nt file2file1file2 新。
file1 -ot file2file1file2 老。
-d file文件file存在,且是一个文件夹。
-e file文件 file 存在。
-f file文件file存在,且为普通文件。
-L file文件file存在,且为符号连接。
-O file文件 flle 存在, 且由有效用户 ID 拥有。
-r file文件 flle 存在, 且是一个可读文件。
-s file文件 flle 存在, 且文件大小大于 0。
-w file文件 flle 可写入。
-x file文件 flle 可写执行。

可以使用 man test 查看详细的说明。

当表达式为 True 时,测试命令返回退出状态 0,而表达式为 False 时返回退出状态1。

#!/bin/bash
FILE="/etc/resolv.conf"
if [ -e "$FILE" ]; then
  if [ -f "$FILE" ]; then
      echo "$FILE is a file."
  fi
  if [ -d "$FILE" ]; then
      echo "$FILE is a directory."
  fi
  if [ -r "$FILE" ]; then
      echo "$FILE is readable."
  fi
fi

字符串比较表达式 #

表达式True
string1 = string2string1 == string2两字符相等
string1 != string2两个字符串不相等
string1 > string2string1 大于 string2.
string1 < string2string1 小于string2.
-n string字符串长度大于0
-z string字符串长度等于0
#!/bin/bash
STRING=""
if [ -z "$STRING" ]; then
  echo "There is no string." >&2 
  exit 1
fi

# Output
# There is no string.

其中 >&2 将错误信息定位到标准错误输出。

数字比较表达式 #

下面这些是用来比较数字的一些表达式。

[…]((…))True
[ “int1” -eq “int2” ](( “int1” == “int2” ))相等.
[ “int1” -nq “int2” ](( “int1” != “int2” ))不等.
[ “int1” -lt “int2” ](( “int1” < “int2” ))int2 大于 int1.
[ “int1” -le “int2” ](( “int1” <= “int2” ))int2 大于等于 int1.
[ “int1” -gt “int2” ](( “int1 > “int2” ))int1 大于 int2
[ “int1” -ge “int2” ](( “int1 >= “int2” ))int1 大于等于 int2

shell 运算符 #

算数运算符 #

val1=`expr 2 + 2`
val2=`expr 2 - 2`
val3=`expr 2 \* 2` # *前面必须加\
val4=`expr 2 / 2`
val5=`expr 2 % 2`

echo "2 + 2: $val1"
echo "2 - 2: $val2"
echo "2 * 2: $val3"
echo "2 / 2: $val4"
echo "2 % 2: $val5"

注意:

  • 使用反引号而不是单引号;
  • 关键字expr;
  • 运算符如:+-*/% 字符前后都需要空格,否则被认为是字符串

其他算数运算符:

运算符说明示例
=赋值a=$b
==判等[ $a == $b ] 返回0
!=不等[ $a != $b ] 返回1

关系运算符 #

运算符说明示例
-eq等于[ $a -eq $b ]
-ne不等于
-gt大于
-lt小于
-ge大于等于
-le小于等于

注意:

  • 关系运算符只适用于数字,不支持字符串,除非字符串的值是数字

布尔运算符 #

运算符说明示例
!非运算[ $a != $b ]
-o或运算[ $a -eq $b -o $c -eq $d ]
-a与运算[ $a -eq $b -a $c -eq $d ]

逻辑运算符 #

运算符说明示例
&&与运算[[ $a -eq $b && $c -eq $d ]]
||或运算`[[ $a -eq $b

说明:

  • 需要两层[]

字符串运算符 #

运算符说明示例
=判等[ $a = $b ]
!=不等[ $a != $b ]
-z字符长度是否为0[ -z $a ]
-n字符串长度不为0[ -n $b ]
$字符串不为空,empty或whitespace[ $a ]

文件测试运算符 #

运算符说明示例
-b file是否为块设备文件[ -b $filepath ]
-c file是否为字符设备文件
-d file是否为目录
-f file是否为普通文件(非设备文件)
-g file是否设置SGID位
-k file是否设置了粘着位(sticky bit)
-p file是否有名管道
-u file是否设置SUID位
-r file是否可读
-w file是否可写
-x file是否可执行
-s file是否不为空文件(文件大小为0)
-e file文件(目录)是否存在
-S file文件是否socket
-L file文件是否存在并且是一个符号链接

shell 命令 #

echo #

打印字符串:

  • 可以是带双引号,单引号,不带引号
  • 可以转义
  • 可以用参数
echo "Hello World"
echo 'Hello World'
echo Hello World

name="Ding Peng"
echo "Hello, $name!"

# -e 开启转义
echo -e "Hi Ding,\n" # 两行之间空一行
echo "Nice to meet you."

echo -e "Hi Jay,\c"  # 不会换行,都在一行内输出
echo "Nice to meet you." 

echo -e "Hi James,\r" # 会换行,但是没有\r也会默认换行的。
echo -e "Nice to meet you."

打印到某文件:

echo "Hello World" > temp.txt 

变量不转义,原样输出:

echo '$name'
echo '\*'

说明:

  • 需要用单引号

显示命令执行结果:

echo `date`

说明:

  • 使用反引号,不是单引号

read #

交互,获取控制台输入并赋值给某变量

read name
echo $name

printf #

输出命令,移植性优于echo。默认不换行,可以在字符串后添加\n

printf "Hello\n" 

通过以下脚本学习printf命令的一些格式化功能

printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg  
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543 
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876 
  • %s %c %d %f都是格式替代符
  • %-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
  • %-4.2f 指格式化为小数,其中.2指保留2位小数。

shell 变量引用 #

当你要使用变量的时候,用 $ 来引用, 如果后面要接一些其他字符,可以用 {} 括起来。

#!/bin/bash
WORLD="world world"
echo "hello $WORLD"  # hello world world
echo "hello ${WORLD}2" # hello world world2

在 Bash 中要注意 单引号 ' ,双引号 " ,反引号 ` 的区别。

单引号,双引号都能用来保留引号内的为文字值,其差别在于,双引号在遇到 $(参数替换) ,反引号 `(命令替换) 的时候有例外,单引号则剥夺其中所有字符的特殊含义。

而反引号的作用 和 $() 是差不多的。 在执行一条命令的时候,会先执行其中的命令,再把结果放到原命令中。

#!/bin/bash
var="music"
sports='sports'
echo "I like $var"   # I like music
echo "I like ${var}" # I like music
echo I like $var     # I like music
echo 'I like $var'   # I like $var
echo "I like \$var"  # I like $var
echo 'I like \$var'  # I like \$var
echo `bash -version` # GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)...
echo 'bash -version' # bash -version

shell 经典实例 #

删除确认 #

#!/bin/bash
delete_sure
delete_sure(){
  cat << eof
$(echo -e "\033[1;36mNote:\033[0m")
Delete the KubeSphere cluster, including the module kubesphere-system kubesphere-devops-system kubesphere-monitoring-system kubesphere-logging-system openpitrix-system.
eof

read -p "Please reconfirm that you want to delete the KubeSphere cluster.  (yes/no) " ans
while [[ "x"$ans != "xyes" && "x"$ans != "xno" ]]; do
    read -p "Please reconfirm that you want to delete the KubeSphere cluster.  (yes/no) " ans
done

if [[ "x"$ans == "xno" ]]; then
    exit
fi
}

« shell 命令间隔符

» 使用 SSH Tunnel 连接中间件