Linux 系统命令及Shell脚本实践指南
- [《Linux 系统命令及Shell脚本实践指南》](#《Linux 系统命令及Shell脚本实践指南》)
-
- 该书从结构上分为三部分:
-
- 第一部分
- 第二部分
-
- [vi 文件名 或者 vim 文件名](#vi 文件名 或者 vim 文件名)
- 基于流处理的sed,处理行
- 基于流处理的awk,处理列
- 第三部分
-
- 定义变量、数组
- [测试结构 test 或者 [ ]](#测试结构 test 或者 [ ])
- if/elif/else
- case...esac
- for/while
- 函数
- 其它
《Linux 系统命令及Shell脚本实践指南》
该书从结构上分为三部分:
主要侧重于应用实操,是一本实践指南。通读本书,我觉得不足之处就是没有展示内存管理部分。
第一部分
为第一章到第八章,为基础内容,详细的介绍了Linux的历史发展、
安装使用、用户管理、文件管理、文件系统、字符处理、网络管理、进程管理和软件安装
查看命令用法
man 命令名称 如果该命令说明文档很长:输入man 页数 命令名称
命令名称 --help
查看内建命令 help -d
命令替换$() 、``,所谓 命令替换就是可以执行命令的
两者相比,前者可读性更强,支持命令嵌套:如:result=$(command1 $(command2))
命令取别名:alias ll='ls -la'
1.1Linux的历史发展
免费、开源、1991年由芬兰大学生编写的Minix延伸而来,这位大学生就是后来的Linux之父【Linus Torvalds】
1.2用户管理
查看用户:users、who、w
调查用户:finger 用户名
切换用户:su【普通用户使用】和sudo【超级用户使用,即root用户】使用root用户的权限进行操作
增删改查用户、用户组
1.3任务管理
单一时刻执行一次任务使用at
周期性任务使用:cron表达式,命令crontab
crontab -e 编辑
crontab -l 查看
crontab -r 删除
1.4文件管理
相对路径:如./ 【表示在当前目录下】和.../【表示在当前目录的上一级目录】
touch 文件名 【创建文件】
rm 文件名 【删除文件remove】--》rm -rf /test/myfile/*【-rf是敏感操作,慎用】
mv 文件名 目录/新的文件名【移动或重命名文件】
如果第二个参数是目录,表示移动:如 mv 1.txt /myfile/test
如果第二个参数是文件名,表示重命名:如 mv 1.txt myNewName.txt
如:mv 1.txt /myfile/test/myNewName.txt【移动到指定文件夹下同时重命名】
cat -n 文件名【查看文件】
head/tail -n 要查看的行数 文件名,如 tail -n 1000 文件名
实时查看文件尾:tail -f 文件名 【或文件的全路径】
cp 1.txt 111.txt【复制文件】
cp 1.txt /myfile/test/111.txt【复制文件且重命名】
cp 1.txt /myfile/test/【复制文件但不重命名】
复制目录也是使用 cp 命令 但是需要使用 -r参数 否则不生效 如:cp -r aa bb
切换目录:cd ,
查看目录中的文件列表 ls -la ,
创建目录 mkdir -p 目录名
查看当前目录 pwd
1.4.1 Linux shell 文件名中的通配符
在Linux的Shell中,通配符是一种用于匹配文件名的特殊字符。
它们可以帮助你在命令中指定一组文件名模式,以便进行文件操作。以下是一些常用的通配符及其用法:
星号(*):匹配任意字符(包括空字符)的任意长度。例如,*.txt可以匹配所有以.txt结尾的文件名。
问号(?):匹配任意单个字符。例如,file?.txt可以匹配类似于file1.txt、file2.txt等的文件名。
方括号([]):匹配方括号中列出的任意一个字符。例如,file[123].txt可以匹配file1.txt、file2.txt或file3.txt。
范围(-):在方括号中使用范围来匹配一定范围内的字符。例如,file[a-z].txt可以匹配以file开头、后面跟着任意小写字母、最后以.txt结尾的文件名。
反向范围([^]):在方括号中使用反向范围来匹配不在范围内的字符。
例如,file[^0-9].txt可以匹配以file开头、后面跟着任意非数字字符、最后以.txt结尾的文件名
这些通配符可以与命令一起使用,如ls、cp、rm等,以匹配符合特定模式的文件名。你可以根据需要使用不同的通配符来进行文件操作
1.5 改变文件权限 chmod
分别用user、group、others 来代表文件拥有者、拥有组、其他人的权限,简写 u、g 、o
分别使用r、w、x来代表 读、写、和执行权限
定义r用数字4表示,w用数字2表示,x用数字1表示。
假如我们想设置一个文件的权限是:
拥有者的权限是:读写执行 【rwx】则数字表示为7,拥有组的权限是读、执行 【r-x】则数字表示为5,其他人的权限是只读【r- -】则数字表示为4
就可以使用命令 chmod 754 文件名,来表示,如果需要赋予拥有者、拥有组、其他人的权限都具有读写执行,可以使用chmod 777 文件名
为该目录下所有的文件及其子目录设置权限使用-R参数
chmod -R 777 文件名
1.6网络管理
ping
ifconfig
1.7进程管理
ps -ef |grep java 【查看java相关进程】
lsof【list open file 】
top 【相当于window中的资源管理器】,而ps是进程快照
kill -9 进程id号
1.8 查看内存使用情况
free -h
free -m
1.9 查看磁盘空间
df -h
第二部分
第二部分是本书的第九章到第十章,为编辑部分。
内容为Linux下常用的vi和vim的用法和基于流处理的sed和awk工具。这是管理Linux的基本技能。
vi 文件名 或者 vim 文件名
按 a或i 进入编辑模式,按esc键退出编辑模式,在英文模式下,按:wq保存并退出
查找模式
进入文件内容后,
使用/从头开始查找,输入要查找的字符串,按回车即可查找,按n下一个,按shift+n 查找上一个
使用?从尾部开始查找
基于流处理的sed,处理行
Linux sed 命令是利用脚本来处理文本文件。
sed 可依照脚本的指令来处理、编辑文本文件。
Sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。
shell
# g 标识符表示全局查找替换,使 sed 对文件中所有符合的字符串都被替换,修改后内容会到标准输出,不会修改原文件:
sed -e 's/oo/kk/g' 文件名
基于流处理的awk,处理列
AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。
之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。
shell
# 每行按空格或TAB分割【默认】,输出文本文件中的第一列和第四列
awk '{print $1,$4}' log.txt
# 使用awk -F #-F相当于内置变量FS, 指定分割字符,指定使用逗号分割
awk -F, '{print $1,$2}' log.txt
第三部分
第三部分为本书的第十一章到第十八章,为shell编程部分。
第一部分和第二部分都是为了给第三部分做铺垫,只有有了前面两个部分的基础,编写shell脚本才能得心应手。
内容包括shell的安装、使用、语法,其中最后一章是第三部分的重点,该章所有的脚本在实际应用中有很高的使用率。
shell 作为一门脚本编程语言,既然是编程语言,就会有变量、转义引用、运算符、特殊字符、if/elif/else、case等逻辑判断结构、
有for、while等循环语句,最后加上函数和输入输出重定向。
定义变量、数组
shell
#!/usr/bin/env bash
# 查找bash 所在位置:
whereis bash
echo 'hello world!'
# 定义变量,等号前后不能有空格
your_name="ljh"
echo '使用双引号拼接'
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
echo '使用单引号拼接'
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2 $greeting_3
echo "ddd长度是:${#greeting_2}"
echo "截取后的字符串是:${greeting:1:4}"
str="xk is a great site"
echo `expr index "$str" io` # 输出 4:
echo "用括号来表示数组,数组元素用\"空格\"符号分割开"
arr=(1 2 3 4 5 6)
echo "打印数组中的所有元素:${arr[@]}"
echo "打印数组中的第一个元素:${arr[0]}"
# 取得数组元素的个数
echo "取得数组元素的个数 ${#arr[@]}"
# 或者
echo "取得数组元素的个数 ${#arr[*]}"
echo "多行注释【:<<注释标识符】,例如:这里的注释标识符是remark 可以替换成其它字符:rem等"
:<<remark
我是小孩也是王
我是
我
remark
echo "多行注释2"
:<<rem
我是小孩也是王
我是
我
rem
echo "Shell 传递参数实例!例如执行:./my.sh 我是 小孩 也是王";
echo "美元符0表示文件名 执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
echo "脚本参数的个数是:$#"
echo "脚本参数的所有元素是:$*"
echo "脚本运行的进程id号是:$$"
echo "上一个命令是否执行成功:$?"
echo "shell 使用的当前选项:$-"
echo "查询最后10条历史命令 history | tail -n 10"
#数值计算
echo "$((1+1))"
echo "$[1+1]"
#命令替换 $(),可以执行命令,将命令执行后的结果赋值给变量
echo "$(ls -la)"
测试结构 test 或者 [ ]
如果使用[ ]判断,[]里里外外都要有空格
逻辑测试
-a 表示且关系
-o 表示或关系
! 表示非
()表示优先级
字符串测试
【所有的字符变量都要加双引号"$string1"】
test -n 字符串
字符串长度非0
test -z 字符串
字符串长度为0
test 字符串 = 字符串2
测试字符串是否相等
test 字符串 != 字符串2
测试字符串不相等
字符串的比较
在Shell中,用于字符串比较的运算符是=而不是==。==运算符通常在条件语句中用于字符串比较,但它是Bash Shell的扩展语法,不是标准的Shell语法。
在标准的Shell语法中,应该使用=运算符来进行字符串比较。以下是使用=运算符进行字符串相等判断的示例:
shell
if [ "$string1" = "$string2" ]; then
# code to be executed if strings are equal
fi
#请注意,在使用=运算符进行字符串比较时,变量应该用双引号括起来,以避免在比较时出现意外的结果。如果你在标准的Shell环境中,并且需要进行字符串比较,请使用=运算符而不是==运算符
#当在字符串比较时,如果没有将变量用双引号括起来,可能会导致以下情况下的意外结果:
#1. 空字符串问题:如果变量的值为空字符串,而在比较时没有使用双引号括起来,可能会导致语法错误或比较结果不符合预期
#提示的错误为 -bash: [: =: unary operator expected
string1=""
string2="hello"
if [ $string1 = $string2 ]; then
echo "Strings are equal"
else
echo "Strings are not equal"
fi
#2. 包含空格或特殊字符问题:如果变量的值包含空格或特殊字符,而在比较时没有使用双引号括起来,可能会导致比较结果不符合预期。
#提示的错误为 -bash: [: too many arguments
string1="hello world"
string2="hello"
if [ $string1 = $string2 ]; then
echo "Strings are equal"
else
echo "Strings are not equal"
fi
bash
#判断两个字符串是否相等
#1. 使用=运算符:
if [ "$string1" = "$string2" ]; then
echo "Strings are equal"
fi
#2. 使用==运算符(Bash特有):
if [ "$string1" == "$string2" ]; then
echo "Strings are equal"
fi
#3. 使用双方括号[[ ]]结构(Bash特有):
if [[ "$string1" = "$string2" ]]; then
echo "Strings are equal"
fi
#4. 使用test命令:
if test "$string1" = "$string2"; then
echo "Strings are equal"
fi
#这些方式都可以用于判断两个字符串是否相等。需要注意的是,字符串变量应该用双引号括起来,以避免在比较时出现意外的结果。选择适合你的Shell环境和编码风格的方式来进行字符串相等的判断
数值测试【可以使用[ ]、[[ ]]、(( ))】
-eq【相等】 、-ne【不等于】 、-gt【大于】、-ge【大于等于】、-lt【小于】、-le【小于等于】
文件测试
-e 文件是否存在
-f 是否是普通文件
-d 是否是目录
if/elif/else
bash
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
# 示例
a=10
b=20
if [ $a -ge $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
elif [ $a -lt $b ]
then
echo "a 小于 b"
else
echo "没有符合的条件"
fi
# 如果使用 ((...)) 作为判断语句,大于和小于可以直接使用 > 和 <。
a=10
b=20
if (( $a == $b ))
then
echo "a 等于 b"
elif (( $a > $b ))
then
echo "a 大于 b"
elif (( $a < $b ))
then
echo "a 小于 b"
else
echo "没有符合的条件"
fi
case...esac
bash
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum #从键盘中读取数字
case $aNum in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac
for/while
bash
# for循环格式
# 当变量值在列表里,for 循环即执行一次所有命令,使用变量名获取列表中的当前取值。
#命令可为任何有效的 shell 命令和语句。in 列表可以包含替换、字符串和文件名。
#in列表是可选的,如果不用它,for循环使用命令行的位置参数。
# for each 形式
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
#示例
for i in {2,4,6,8};
do
echo "$i";
done
# 1到10
for i in {1..10};
do
echo "$i";
done
# 前缀
for i in user{1..10};
do
echo "$i";
done
# 写成一行
for i in {2,4,20};do echo $(($i*3));done
sum=0;
for i in {1..10};do let sum+=$i;done
for i in `ls`;do echo "$i";done
for i in *.txt;do echo "$i";done
for i in `seq 1 2 10`;do echo "$i";done
# fori 形式
for (( exp1; exp2; exp3 ));
do
COMMANDS;
done
# 示例
sum=0;
for ((i=1;i<=10;i++));do let sum+=$i;echo "$sum";done
while COMMANDS;
do
COMMANDS;
done
#示例1
num=10
while [ $num -gt 0 ]
do
echo $num;
num=$((num-1));
done
#示例2 注意写法上的区别,((...))中可以直接使用大于小于等比较符,而无需使用
# -eq【相等】 、-ne【不等于】 、-gt【大于】、-ge【大于等于】、-lt【小于】、-le【小于等于】
num=10
while (($num > 0))
do
echo $num;
num=$((num-1));
done
#批量创建用户
count=1
while [ $count -le 5 ]
do
userName="user$count"
useradd $userName
echo "User $userName created."
count=$((count+1))
done
函数
bash
# 定义函数
function myFunc () {
echo "haha";
}
#调用函数
myFunc
# 定义函数
function resultOfSum(){
let c=${1}+${2}
echo ${c}
}
# 调用带参函数
resultOfSum 1 2
function add(){
sum=$[$1 + $2]
#echo "sum="$sum
#return "sum="$sum # 自定义函数的return只能返回整数
echo $sum
}
read -p "请输入第一个整数:" a
read -p "请输入第二个整数:" b
sum=$(add $a $b)
echo "sum="$sum
其它
多行输入
在大多数情况下,Shell脚本中的命令和语句都可以通过换行符进行分隔,而不需要使用分号。分号主要用于在同一行上写多个命令或语句
使用反斜杠(\):你可以使用反斜杠来继续输入下一行
bash
command \
command1 \
command2 \
command3
shell中的计算
在Linux的Shell中,有一些命令和操作符是用于计算的。以下是一些常用的计算命令和操作符:
- expr命令:用于执行基本的算术和字符串操作。它可以进行加法、减法、乘法、除法和取模等运算。例如:
result=$(expr 5 + 3)
echo $result
- let命令:用于执行算术运算和赋值操作。它支持基本的算术运算符(如+、-、*、/、%)和逻辑运算符(如&&、||、!)。例如:
let result=5+3
echo $result
- $(( ))操作符:用于执行算术运算。它支持基本的算术运算符和逻辑运算符,并且可以嵌套使用。例如:
result=$((5 + 3))
echo $result
- bc命令:用于执行高级数学运算,如平方根、指数、对数等。它支持数值计算和数学函数。例如:
result=$(echo "sqrt(16)" | bc)
echo $result
bc命令除了可以在命令行中执行数学计算,还可以进入终端交互模式,允许用户逐行输入数学表达式进行计算。例如:
bc 5 + 3
-
\[\]操作符:是一种旧式的算术运算符,用于执行基本的算术运算。它类似于(( ))操作符,用于计算数学表达式并返回结果
然而,需要注意的是,\[\]是一种旧式的语法,不如(( ))操作符常用。在现代的Shell环境中,推荐使用$(( ))操作符来进行算术运算,因为它更易读和易于理解
result=$[5 + 3]
echo $result
这些命令和操作符可以帮助你在Shell脚本中进行基本的算术和数值计算。你可以根据具体的需求选择适合的命令或操作符来进行计算
shell中 ,[] 和[[ ]]的区别是什么?
在Shell中,[]和[[]]是用于条件测试的两种不同的语法结构,它们有一些区别:
-
[](方括号)是传统的条件测试结构,也被称为test命令。它是Shell的内置命令,用于进行条件判断。
[]中的条件表达式可以使用标准的比较运算符(如-eq、-ne、-lt、-gt等)和逻辑运算符(如-a、-o、!等)。例如:
if [ $num -eq 5 ]; then
echo "Number is equal to 5"
fi
-
[[ ]](双方括号)是Bash Shell的扩展语法,提供了更强大和灵活的条件测试功能。
[[ ]]结构支持更多的比较运算符(如==、!=、<、>等)和模式匹配(如*、?、[...]等)。
它还支持逻辑运算符(如&&、||、!)和正则表达式匹配。例如:
if [[ $num == 5 ]]; then
echo "Number is equal to 5"
fi
- [[ ]]结构相对于[]结构还有其他一些优点,如更好的字符串处理能力、更灵活的变量扩展和更安全的文件名扩展。它还支持嵌套条件和更复杂的逻辑表达式。但需要注意的是,[[ ]]结构只在Bash Shell中可用,不适用于其他Shell(如dash等)。
总的来说,[]是传统的条件测试结构,适用于基本的条件判断。而[[ ]]是Bash Shell的扩展语法,提供了更强大和灵活的条件测试功能。如果你在Bash环境中,并且需要更复杂的条件判断和字符串处理,建议使用[[ ]]结构
shell中 ,()和(())的区别是什么?
在Shell中,()和(())是两种不同的语法结构,它们有以下区别:
- ()(圆括号)用于创建子shell或命令组。当命令被放置在()中时,它们将在一个子shell中执行,这意味着其中的变量和环境将在子shell中创建和修改,不会影响到父shell。例如:
(command1; command2; command3)
- (())(双圆括号)用于执行算术运算和数值比较,而不是用于字符串比较,它支持整数运算、变量赋值和逻辑比较。在(())中,不需要使用$符号来引用变量。例如:
((x = 5 + 3))
或者
运算符前后需要有空格
x=9;
if ((x > 10)); then
echo "x is greater than 10"
fi
不建议使用(())进行字符串比较
x="hha"
if ((x == "hha")); then
echo "equal"
fi
尽管在正常情况下,(())结构主要用于数值运算和比较,但在某些Shell环境中,也可以用于字符串比较。
在Bash Shell中,(())结构可以进行字符串比较,但它会将字符串作为数值进行处理。当字符串可以被解释为有效的数值时,(())结构会将其转换为数值进行比较。如果字符串无法解释为有效的数值,则会产生错误。
在你的示例中,字符串x的值是"hha",它无法解释为有效的数值。然而,在某些Shell环境中,(())结构会将字符串作为0来处理,因此比较结果为真,进入了if语句块并输出"equal"。
尽管在某些Shell环境中可以使用(())结构进行字符串比较,但这种用法并不常见,容易引起混淆。为了更清晰和可读的代码,建议使用其他方式来进行字符串比较,如使用=或==运算符、test命令、[[ ]]结构或case语句
(())结构还支持位运算、递增和递减操作等。
总的来说,()用于创建子shell或命令组,而(())用于执行算术运算和数值比较。它们在功能和用法上有明显的区别,因此需要根据具体的需求选择适合的语法结构
在(())中,不需要使用符号来引用变量,因为(())结构会自动识别和处理变量。如果你在(())中使用了符号来引用变量,也不会导致语法错误。
例如,下面是一个正确的(())示例:
if (( $a == $b ))
和
if (( a == b ))
等价