logo

Shell

王哲峰 / 2022-05-07


目录

Shell 简介

操作系统的核心:Linux Kernel。用户与操作系统之间的接口:Shell、GUI。GUI 提供了一种图形化的用户接口,使用起来非常简便易学

Shell 提供了一种命令行的接口,接收用户的键盘输入,并分析和执行输入字符串中的命令,然后给用户返回执行结果, 使用起来可能会复杂一些,但是由于占用的资源少,而且在操作熟练以后可能会提高工作效率,而且具有批处理的功能, 因此在某些应用场合还非常流行

作为一种用户接口,它实际上是一个能够解释和分析用户键盘输入,执行输入中的命令, 然后返回结果的一个解释程序(Interpreter,Linux 下比较常用的是 Bash)。 该解释程序不仅能够解释简单的命令,而且可以解释一个具有特定语法结构的文件,这种文件被称作 脚本(Script)

查看当前的 Shell:

$ echo $SHELL
$ ls -l /bin/bash
$ ls -l /bin/zsh

搭建运行环境

在一个 Linux 操作系统中,有一个运行有 Bash 的命令行在等待键入命令, 这个命令行可以是图形界面下的 终端(Terminal),例如:Ubuntu 下的 Terminator.

搭建Bash运行环境

# 运行Bash环境
$ chsh $USER -s /bin/bash

$ su $USER

或者

# 切换到Bash运行环境
$ bash

# 确认命令行中运行的是Bash
$ echo $SHELL

运行Shell脚本

方法 1:确保执行的命令具有可执行权限:chmod +x

# 确保执行的命令具有可执行权限
$ chmod +x ./shell/helloworld.sh

# 运行脚本
$ ./shell/helloworld.sh

方法 2:直接把脚本作为 Bash 解释器的参数传入:bash

$ bash ./shell/helloworld.sh

方法 3:source

$ source ./shell/helloworld.sh

方法 4:.

$ . ./shell/helloworld.sh

Shell 基本语法

Shell 的 Hello,World 程序

两种 Shell 程序:

#!/bin/bash -v
# helloworld.sh

echo "Hello, World"

#!/bin/bash
# helloworld.sh

echo "Hello, World"

分析 Shell 程序:

上面两种程序结构对于两种不同的运行方式输出内容有差别:

chmod +x ./shell/helloworld.sh./shell/helloworld.sh 运行结果如下(多打印了脚本文件本身的内容):

#!/bin/bash -v
# helloworld.sh

echo "Hello World"
Hello World

bash ./shell/helloworld.sh 运行结果如下:

Hello World

chmod +x ./shell/helloworld.sh./shell/helloworld.shbash ./shell/helloworld.sh 的运行结果一样,如下:

Hello World

造成上面的结果的原因是在第一种程序结构中的第一行,当直接运行该脚本文件时, 该行告诉操作系统使用 #! 符号之后的解释器以及相应的参数来解释该脚本文件, 通过分析第一行,发现对应的解释器以及参数是 /bin/bash -v,而 -v 刚好就是要打印程序的源代码; 但是我们在用第二种方法时没有给 Bash 传递任何额外的参数,因此,它仅仅解释了脚本文件本身

Shell 变量

定义变量:

$ var_name="wangzhefeng"

使用变量:

$ var_name="wangzhefeng"
$ var_name="zfwang"

$ echo $var_name
$ echo ${var_name}

只读变量:

$ var_name="read only"
$ readonly var_name

删除变量:

$ var_name="wanzhefeng"
$ unset var_name

变量类型:

运行 Shell 时,会同时存在 3 种变量:

  1. 局部变量:
    • 局部变量在脚本或命令中定义,仅在当前Shell实例中有效,其他Shell启动的程序不能访问局部变量
  2. 环境变量:
    • 所有的程序,包括 Shell 启动的程序都能访问环境变量
    • 有些程序需要环境变量来保证其正常运行,必要的时候 Shell 脚本也可以定义环境变量
  3. Shell 变量:Shell 变量是由 Shell 程序设置的特殊变量. Shell 变量中有一部分是环境变量, 有一部分是局部变量,这些变量保证了 Shell 的正常运行

Shell 字符串

Shell 字符串可以用单引号,也可以用双引号,也可以不用引号

单引号:

$ str='this is a string'

双引号:

$ var="wangzhefeng"
$ str="Hello, I know you are \"$var\"! \n"
$ echo -e $str

输出:

Hello, I know you are "wangzhefeng"!

拼接字符串:

$ var1="wangzhefeng"
$ greeting1="hello, "$var1" !"
$ greeting2="hello, ${var1} !"
$ echo $greeting1 $greeting2

输出:

hello, wangzhefeng ! hello, wangzhefeng !
$ var2="wangzhefeng"
$ greet1='hello, '$var2' !' # 单引号可以成对出现,作为字符串拼接的使用
$ greet2='hello, ${var2} !' # 单引号中的变量无效
$ echo greet1 greet2

输出:

hello, wangzhefeng ! hello, ${var2} !

获取字符串长度:

string="abcd"
echo ${#string}

提取字符串:

string="wangzhefeng is a man!"
echo ${string:0:11}

查找子字符串:

# 查找字符串`i`或`o`的位置(哪个字母先出现就计算哪个)
string="wangzhefeng is a man!"
echo `expr index "$string" io`

输出:

13

字符串操作

字符串的属性:

字符串的类型:

字符可能是数字、字符、空格、其他特殊字符,而字符串有可能是它们中的一种或多种的组合, 在组合之后还可能形成具有特定意义的字符串,诸如邮件地址、URL 地址等.

字符串的长度:

计算某个字符串的长度

var="get the length of me"
echo ${var}

# method 1
echo ${#var}

# method 2
expr length "$var"

# method 3
echo $var awk '{printf("%d\n", length($0));}'

# method 4 
 echo -n $var | wc -c

计算某些指定字符或者字符组合的个数

echo $var | tr -cd g | wc -c
echo -n $var | sed -e 's/[^g]//g' | wc -c
echo -n $var | sed -e 's/[^gt]//g' | wc -c

统计单词个数

echo $var | wc -w
echo "$var" | tr " " "\n" | grep get | uniq -c 
echo "$var" | tr " " "\n" | grep get | wc -l

Shell 注释

:<<EOF 
注释
EOF
:<<'
注释
'
:<<!
注释
!
function func_comment() {
    注释
}

Shell传递参数

在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n

参数处理格式 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数. 如 $*"" 括起来的情况
$@ $* 相同,但是使用时加引号,并在引号中返回每个参数.
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$- 显示Shell使用的当前选项,与set命令功能相同.
$? 显示最后命令退出的状态,0表示没有错误,其他任何值表示又错误.
#!/bin/bash
# params.sh

echo "Shell 传递参数!"
echo "第一个参数: $1"
echo "第二个参数: $2"
echo "第三个参数: $3"
echo "传递的参数个数: $#"
echo "传递的参数以一个字符串显示: $*"
echo "传递的参数以多个字符串显示: $@"
echo "Shell使用的当前选项: $-"
echo "Shell最后命令的退出状态: $?"
echo "脚本运行的当前进程ID号: $$"
echo "脚本运行的最后一个进程ID号: $!"

echo "=======\$*的示例========"
for i in "$*"
do 
echo $i
done

echo "=======\$@的示例========"
for i in "$@"
do 
echo $i
done
Shell 传递参数!
第一个参数: param_1
第二个参数: param_2
第三个参数: param_3
传递的参数个数: 3
传递的参数以一个字符串显示: param_1 param_2 param_3
传递的参数以多个字符串显示: param_1 param_2 param_3
Shell使用的当前选项: hB
Shell最后命令的退出状态: 0
脚本运行的当前进程ID号: 21869
脚本运行的最后一个进程ID号: 
=======$*的示例========
param_1 param_2 param_3
=======$@的示例========
param_1
param_2
param_3

Shell 数组

bash支持一维数组,不支持多维数组,并且没有限定数组的大小; 数组元素的下表由0开始编号,获取数组中的元素要利用下标, 下标可以是整数或算术表达式,其值应大于或等于 0

定义数组:

在 Shell 中,用圆括号来表示数组,数组元素用"空格"分割开

arrayName=(elem_1 elem_2 ... elem_n)
arrayName=(
    elem_1
    elem_2
    ...
    elem_n
)
arrayName[0]=elem_1
arrayName[1]=elem_2
arrayName[n]=elem_n

读取数组:

格式:

${数组名[下标]}

示例:

value_n=${arrayName[n]}
echo ${arrayName[@]}

获取数组的长度:

# 取得数组元素的个数
length=${#arrayName[@]}

# or
length=${#arrayName[*]}

# 取得数组单个元素的长度
length_n=${#arrayName[n]}

Shell运算符

#!/bin/bash

val=`expr 2 + 2`
echo "两个之和为: $val"

算术运算符

参数 说明 举例
+ expr :math:a + b
- expr :math:a - b
* expr :math:a * b
/ expr :math:b \ a
% 求余 expr :math:b % a
= 赋值 :math:a=b
= 相等,用于比较两个数字 [ :math:a == b]
!= 不相等,用于比较两个数字 [ :math:a != b ]

关系运算符

参数 说明 举例
-eq 等于,= [ $a -eq $b ]
ne 不等于,!= [ $a -ne $b ]
-gt 大于,> [ $a -gt $b ]
-ge 大于等于,>= [ $a -ge $b ]
-lt 小于,< [ $a -lt $b ]
-le 小于等于,<= [ $a -le $b ]

布尔运算符

参数 说明 举例
! [ !false ]
-o [ $a -lt 20 -o $b -gt 100 ]
-a [ $a -lt 20 -a $b -gt 100 ]

逻辑运算符

参数 说明 举例
&& 逻辑AND [[ $a -lt 100 && $b -gt 100 ]]
两个竖杆 逻辑OR

字符串运算符

运算符 说明 举例
= 检测两个字符串是否相等,相等返回 [ :math:a = b ]
返回 false.
true.
!= 检测两个字符串是否相等,不相等返回 [ :math:a != b ]
返回 true.
true.
-z 检测字符串长度是否为0,为0返回 [ -z $a ] 返回
false.
true.
-n 检测字符串长度是否为0,不为0返回 [ -n “$a” ] 返回
true.
true.
$ 检测字符串是否为空,不为空返回 [ $a ] 返回 true.
true.

文件测试运算符

操作符 说明 举例
-b file 检测文件是否是块设备文件,如果是,则返回 [ -b $file ] 返回
false.
true.
-c file 检测文件是否是字符设备文件,如果是,则返回 [ -c $file ] 返回
false.
true.
-d file 检测文件是否是目录,如果是,则返回 [ -d $file ] 返回
false.
true.
-f file 检测文件是否是普通文件(既不是目录,也不是 [ -f $file ] 返回
设备文件),如果是,则返回 true.
true.
-g file 检测文件是否设置了 [ -g $file ] 返回
SGID false.
位,如果是,则返回
true.
-k file 检测文件是否设置了粘着位(Sticky [ -k $file ] 返回
false.
Bit),如果是,则返回
true.
-p file 检测文件是否是有名管道,如果是,则返回 [ -p $file ] 返回
false.
true.
-u file 检测文件是否设置了 [ -u $file ] 返回
SUID false.
位,如果是,则返回
true.
-r file 检测文件是否可读,如果是,则返回 [ -r $file ] 返回
true.
true.
-w file 检测文件是否可写,如果是,则返回 [ -w $file ] 返回
true.
true.
-x file 检测文件是否可执行,如果是,则返回 [ -x $file ] 返回
true.
true.
-s file 检测文件是否为空(文件大小是否大于0),不 [ -s $file ] 返回
为空返回 true.
true.
-e file 检测文件(包括目录)是否存在,如果是,则返 [ -e $file ] 返回
true.
true.

Shell 命令之 echo,printf,test

echo

echo 用于字符串的输出,可以使用 echo 实现复杂的输出格式控制

显示普通字符串:

echo "It is a test."

echo It is a test.

显示转义字符:

echo "\"It is a test\""

echo \"It is a test\"

显示变量

#!/bin/bash

read name
echo "$name It is a test"

显示换行

# -e: 开启转义
echo -e "OK! \n"
echo "It is a test"

显示不换行

#!/bin/bash

# -e: 开启转义, \c不换行
echo -e "OK! \c"

显示结果定向至文件

echo "It is a test" > myfile

原样输出字符串,不进行转义或取变量(用单引号)

echo '$name\'

显示命令执行结果

echo `date`

printf

Shell 中的 printf 命令模仿 C 程序库中的 printf()

格式

printf format-string args

示例

手动添加换行符:

$ echo "wangzhefeng"

$ printf "wangzhefeng\n"

格式化打印字符串:

#!/bin/bash

printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2s\n" name1 gender1 66.1234
printf "%-10s %-8s %-4.2s\n" name2 gender2 77.2234
printf "%-10s %-8s %-4.2s\n" name3 gender3 88.3234

printf "%d %s\n" 1 "abc"
printf '%d %s\n' 1 "abc"
printf %s abcdef

# 格式只指定了一个参数, 但多出的参数仍然会按照该格式输出, format-string 被重用
printf %s abc def
printf "%s\n" abc def
printf "%s %s %s\n" a b c d e f g h i j k

# 如果没有 arguments, 那么 %s 用NULL代替, %d 用 0 代替
printf "%s and %d \n"

转义字符:

printf "a string, no processing:<%s>\n" "A\nB"
printf "a string, no processing:<%b>\n" "A\nB"

test

Shell 中的 test 命令用于检查某个条件是否成立,可以进行多种测试

数值测试

参数 说明
-eq 等于,=
-ne 不等于,!=
-gt 大于,>
-ge 大于等于,>=
-lt 小于,<
-le 小于等于,<=

示例

num1=100
num2=100

if test $[num1] -eq $[num2]
then
echo "两个数字相等"
else
echo "两个数字不相等"
if
#!/bin/bash

a=5
b=6

result=$[a+b]
echo "result 是: $result"

字符测试

参数 说明
= 等于
!= 不等于
-z string 字符串的长度为零则为真
-n string 字符串的长度不为零则为真

示例

str1="wangzhefeng"
str2="tinker"

if test $str1 = $str2
then
echo "两个字符串相等"
else
echo "两个字符串不相等"
fi

文件测试

参数 说明
-e filename 如果文件存在则为真
-r filename 如果文件存在且可读则为真
-w filename 如果文件存在且可写则为真
-x filename 如果文件存在且可执行则为真
-s filename 如果文件存在且至少有一个字符则为真
-d filename 如果文件存在且为目录则为真
-f filename 如果文件存在且为普通文件则为真
-c filename 如果文件存在且为字符型特殊文件则为真
-b filename 如果文件存在且为特殊文件则为真

示例

cd /bin

if test -e ./bash
then
echo "文件已存在"
else
echo "文件不存在"
fi

逻辑操作符

Shell 提供了与,或,非逻辑操作符用于将测试条件连接起来,优先级为: > -a > -o

参数 说明
-a 与,and
-o 或,or
! 非,not
cd /bin

if test -e ./notfile -o -e ./bash
then 
echo "至少有一个文件存在"
else
echo "两个文件都不存在"
fi

Shell 流程控制

if…else

if语句

if [test] condition
then 
command1
command2
...
commandN
fi

or

if condition then commands fi

if…else…语句:

if [test] condition
then 
command1
command2
...
commandN
else
commandM
fi

if…elif…else…语句:

if [test] condition1
then 
command1
elif [test] condition2
then 
command2
else
command3
fi

case 语句

Shell case 语句为多选语句,可以用 case 语句匹配一个值与一个模式, 如果匹配成功,执行相匹配的命令

格式:

case value in
mode1)
command1
command2
...
commandN
;;
mode2)
command1
command2
...
commandN
;;
esac

示例:

echo "输入1到4之间的数字:"
echo "你输入的数字为:"
read aNum

case $aNum in
1) echo "你选择了 1"
;;
1) echo "你选择了 2"
;;
1) echo "你选择了 3"
;;
1) echo "你选择了 4"
;;
*) echo "你没有输入1到4之间的数字"
;;
esac

for循环

普通格式:

for var in item1 item2 ... itemN
do 
command1
command2
...
commandN
done

or

for var in item1 item2 ... itemN do command1 command2 ... commandN done

无限循环格式:

for (( ; ;))

while 语句

普通格式:

while condition
do 
command
done

无限循环格式:

while :
do
command
done

or

while true
do
command
done

示例:

#!/bin/bash

int=1
while (($int<=5))
do 
echo $int
let "int++"
done

until 循环

until 循环执行一系列命令直至条件为 true 时停止,condition 一般为条件表达式, 如果返回值为 false,则继续执行循环体内的语句,否则跳出循环;until 循环与 while 循环在处理方式上刚好相反; 一般 while 循环优于 until 循环,但在某些时候 until 循环更加有用

格式:

until condition
do 
command
done

示例:

#!/bin/bash

a=0
until [!$a -lt 10]
do 
echo $a
a=`expr $a + 1`
done

跳出循环

break

break 命令允许跳出所有循环(终止执行后面的所有循环)

示例:

#!/bin/bash

while :
do
echo -n "输入1到5之间的数字:"
read aNum
case $aNum in
	1|2|3|4|5) echo "你输入的数字是: $aNum"
	;;
	*) echo "你输入的数字不是1到5之间的; "
		break
	;;
esac
done

continue

continue 不会跳出所有循环,仅仅跳出当前循环

示例:

#!/bin/bash

while :
do 
echo -n "输入1到5之间的数字:"
read aNum
case $aNum in
	1|2|3|4|5) echo "你输入的数字为: $aNum !"
	;;
	*) echo "你输入的数字不是1到5之间的; "
		continue
		echo "游戏结束"
	;;
esac
done

Shell 函数

函数定义形式:

function fun_name(){
action;

return
}
fun_name(){
action;
return
}
fun_name param1, param2, param3, ...

函数定义示例:

#!/bin/bash
# author: zfwang
# file: demo.sh

demoFun(){
  echo "This is my first Shell function!"
}

# 函数调用
echo "-----函数开始执行-----"
demoFun
echo "-----函数执行完毕-----"
#!/bin/bash
# author: zfwang
# file: funWithReturn.sh

funWithReturn(){
  echo "这个函数会对输入的两个数字进行相加运算..."
  echo "输入第一个数字: "
  read aNum
  echo "输入第二个数字: "
  read anothreNum
  echo "两个数字分别位 $aNum 和 $anotherNum !"
  return ${$aNum+$anotherNum}
}

# 函数调用
funWithReturn
echo "输入的两个数字之和为: $? !"
#!/bin/bash
# author: zfwang
# file: funWithParam.sh

funWithParam(){
echo "第一个参数为 $1 !"
   echo "第二个参数为 $2 !"
   echo "第十个参数为 $10 !"
   echo "第十个参数为 ${10} !"
   echo "第十一个参数为 ${11} !"
   echo "参数总数有 $# 个!"
   echo "作为一个字符串输出所有参数 $* !"
}

# 函数调用
funWithParam 1 2 3 4 5 6 7 8 9 34 73

Shell 输入输出重定向

重定向命令:

命令 说明
command > file 将输出重定向到file
command >> file 将输出以追加的方式重定向到file
command 2 > file 将stderr重定向到file
command 2 >> file 将stderr以追加的方式重定向到file
command < file 将输入重定向到file
command < infile > outfile 对stdin和stdout同时重定向
n >& m 将输出文件m和n合并
n <& m 将输入文件m和n合并
command > file 2>&1 将stdout和stderr合并后重定向到file
command » file 2>&1 将stdout和stderr合并后以追加的方式重定向到file
n > file 将文件描述符为n的文件重定向到file
n >> file 将文件描述符为n的文件以追加的方式重定向到file
<<tag 将开始标记tag和结束标记tag之间的内容作为输入

输出重定向

语法:

command > file
command >> file

示例:

# 将命令的完整的输出重定向到users文件中
who > users

# 查看users文件中的内容
cat users
# 将输出重定向覆盖users文件中的内容
echo "This is a test command by wangzhefeng" > users

# 查看users文件中的内容
cat users
# 将输出重定向追加到users文件的末尾
echo "This is another test command by wangzhefeng" >> users

输入重定向

本来需要从键盘获取输入的命令会转移到文件读取内容

语法:

command < file

示例:

# 统计users文件中的行数(会输出文件名users)
wc -l users

# 统计users文件中的行数(不会输出文件名users)
wc -l < users
# 同时替换输入和输出,执行command,从文件infile读取内容, 然后将输出写入到outfile中
command < infile > outfile

Here Document

Here Document 将输入重定向到一个交互式 Shell 脚本或程序

基本形式:

# 将两个delimiter之间的内容(document)作为输入传递给command
command << delimiter
document
delimiter

示例:

# 通过wc -l 命令计算Here Document的行数
wc -l << EOF
test line 1
test line 2
test line 3
EOF
#!/bin/bash
# hereDocument.sh

cat << EOF
test line 1
test line 2
EOF

/dev/null 文件

格式:

command > /dev/null

示例:

# 屏蔽stdout和stderr
command > /dev/null 2>&1

Shell文件包含

Shell可以包含外部脚本,可以很方便的封装一些公用的代码作为一个独立的文件

格式:

. fileName

# or

source fileName

示例:

创建两个Shell脚本文件:test1.shtest2.sh.并在 test2.sh中调用 test1.sh

#!/bin/bash
# file: test1.sh

string1="wangzhefeng in test1.sh"
#!/bin/bash
# file: test2.sh

# 使用`.`来引用test1.sh文件
. ./shell/test1.sh

# 使用`source`来引用test1.sh文件
source ./shell/test1.sh

echo "在test1.sh中的字符串为: $string1"

执行 test2.sh 脚本:

chmod +x ./shell/test2.sh
./shell/test2.sh

输出

在test1.sh中的字符串为: wangzhefeng in test.sh

Shell 程序设计过程

Shell 语言作为解释型语言,它的程序设计过程跟编译型语言有些区别,其基本过程如下:

可见它没有编译型语言的"麻烦的"编译和链接过程,不过正是因为这样, 它出错时调试起来不是很方便,因为语法错误和逻辑错误都在运行时出现.

Shell 数值运算

整数运算

对某个数加1:

# test

从1加到某个数:

求余数:

求幂:

Shell 布尔运算

常规的布尔运算

在 Shell 下进行逻辑运算

  1. truefalse
$ if true;then echo "YES"; else echo "NO"; fi
$ if false;then echo "YES"; else echo "NO"; fi
  1. 与运算、或运算、非运算
if true && true;then echo "YES"; else echo "NO"; fi
if true && false;then echo "YES"; else echo "NO"; fi
if false && false;then echo "YES"; else echo "NO"; fi
if false && true;then echo "YES"; else echo "NO"; fi
if true || true;then echo "YES"; else echo "NO"; fi
if true || false;then echo "YES"; else echo "NO"; fi
if false || false;then echo "YES"; else echo "NO"; fi
if false || true;then echo "YES"; else echo "NO"; fi
if ! false;then echo "YES"; else echo "NO"; fi
if ! true;then echo "YES"; else echo "NO"; fi

文件操作

文件的各种属性

通过文件的结构体来看看文件到底有哪些属性:

struct stat {
    dev_t st_dev;              /* 设备   */
    ino_t st_ino;     		   /* 节点   */
    mode_t st_mode;   		   /* 模式   */
    nlink_t st_nlink; 		   /* 硬连接 */
    uid_t st_uid;     		   /* 用户ID */
    gid_t st_gid;     		   /* 组ID   */
    dev_t st_rdev;             /* 设备类型 */
    off_t st_off;              /* 文件字节数 */
    unsigned long  st_blksize; /* 块大小 */
    unsigned long st_blocks;   /* 块数   */
    time_t st_atime;           /* 最后一次访问时间 */
    time_t st_mtime;           /* 最后一次修改时间 */
    time_t st_ctime;           /* 最后一次改变时间(指属性) */
};

查看某个文件的属性:

stat file_name
ls -l file_name

文件类型

文件类型对应上面的 st_mode,文件类型有很多,比如:常规文件、符号链接(硬链接、软连接)、 管道文件、设备文件(符号设备、块设备)、socket 文件等,不同的文件类型对应不同的功能和作用

在命令行简单地区分各类文件:

ls -l

简单比较文件的异同:

test

普通文件再分类:

test

文件属主

文件权限

文件大小

文件访问、更新、修改时间

文件名

文件的基本操作

创建文件

$ touch regular_file
$ mkdir directory_file
$ ln regular_file regular_file_hard_link
$ ln -s regular_file regular_file_soft_link
$ mkfifo fifo_pipe
$ mknod hda1_block_dev_file b 3 1
$ mknod null_char_dev_file c 1 3

删除文件

rm regular_file
rmdir directory_file
rm -r directory_file_not_empty

复制文件

$ cp regular_file regular_file_copy
$ cp -r directory_file directory_file_copy

Shell 程序调试方法

用户管理

Linux 用户账号

添加用户

# 创建家目录、指定登录 Shell
$ useradd -s /bin/bash -m test
$ groups test

# 创建家目录、指定登录 Shell、加入所属组
$ useradd -s /bin/bash -m -G docker test
$ groups test

删除用户

# 删除用户以及家目录
$ userdel -r test

修改用户

# 常常用来修改默认的 Shell
$ usermod -s /bin/bash test

# 把用户加入某个新安装软件所属的组
$ usermod -a -G docker test

# 修改登录用户名并搬到新家
$ usermod -d /home/new_test -m -l new_test test

禁用用户

# 禁用某个账号
$ usermod -L test
$ usermod -expiredate 1 test

用户口令

设置口令

$ passwd test

删除口令

# 让用户 test 无需密码登录(密码为空), 这个很方便某些安全无关紧要的条件下(比如已登录主机中的虚拟机), 可避免每次频繁输入密码
$ passwd -d test

修改口令

$ passwd test

禁用口令

$ passwd -l user

Mac 用户、用户组操作

使用 Mac 的时候需要像 Linux 一样对用户和群组进行操作, 但是 Linux 使用的 gpasswdusermod 在 Mac 上都不可以使用, Mac 使用 dscl 来对 groupuser 操作

查看用户组、用户:

$ dscl . list /Groups
$ dscl . list /Users

$ sudo dscl . -list /Groups GroupMembership
$ sudo dscl . -append /Groups/groupname GroupMembership username
$ sudo dscl . -delete /Groups/groupname GroupMembership username

添加用户组、添加用户:

$ sudo dscl . -create /Groups/test

$ sudo dscl . -create /Users/redis

删除用户组、用户:

$ sudo dscl . -delete /Groups/test

$ sudo dscl . -delete /Users/redis