Linux Shell 入门

242 阅读16分钟

1、Linux系统结构图

image.png

2、核心Linux发行版

发行版描述
Slackware最早的linux发行版中的一员,在Linux极客中比较流行
Red Hat主要用于Internet服务器的商业发行版
Fedora从Red Hat分离出的家用发行版
Gentoo为高级Linux用户设计的发行版,仅包含Linux源代码
openSUSE用于商用和家用的发行版
Debian在Linux专家和商用Linux产品中流行的发行版

3、特定用于Linux发行版

发行版描述
CentOS一款基于Red Hat企业版Linux源代码构建的免费发行版
Ubuntu一款用于学校和家庭的免费发行版
PCLinuxOS一款用于家庭和办公的免费发行版
Mint一款用于家庭娱乐的免费发行版
dyne:bolic一款用于音频和MIDI应用的免费发行版
Puppy Linux一款适用于老旧PC的小型免费发行版

4、bash手册

大多数Linux发行版自带用以查找shell命令及其他GUN工具信息的在线手册。熟悉手册对使用各种Linux工具大有裨益,尤其是在你要弄清各种命令行参数的时候。man命令用来访问存储在Linux系统上的手册页面。在想要查找的工具的名称前面输入man命令,就可以找到那个工具相应的手册条目。例如:我们用“man cp”来查看cp的相关命令解释

image.png

image.png

5、常见Linux目录

目录用途
/虚拟目录的根目录,通常不会在这里存储文件
/bin二进制目录,存放许多用户级GUN工具
/boot启动目录,存放启动文件
/dev设备目录。Linux在这里创建设备节点
/etc系统配置文件目录
/home主目录,Linux在这里创建用户目录
/lib库目录,存放系统和应用程序的库文件
/media媒体目录。可移动媒体设备的常用挂载点
/mnt挂载目录,另一个可移动媒体设备的常用挂载点
/opt可选目录,常用于存放第三方软件包和数据文件
/proc进程目录,存放现有硬件及当前进程的相关信息
/rootroot用户的主目录
/sbin系统二进制目录,存放许多GUN管理员级工具
/run运行目录,存放系统运行时的运行时数据
/srv服务目录,存放本地服务的相关文件
/sys系统目录,存放系统硬件信息的相关文件
/tmp临时目录,可以在该目录中创建和删除临时工作文件
/var可变目录,用以存放经常变化的文件,如日志文件

6、基础命令

  • cd:切换目录,cd /usr/bin 表示进入/usr/bin目录
  • pwd:显示所在目录
  • ls:展示列表,ls后面可以加一些附加指令。例如,ls -F:带彩色显示;ls -a:显示包含隐藏文件在内的所有文件;ls -F -R:递归显示文件;ls -l:显示长列表,后面加文件名可以作为过滤条件使用
  • mv:移动文件或重命名,在同级目录下就是重命名,不同目录就是移动
  • rm:删除命令
  • mkdir:创建目录
  • rmkdir:删除目录,仅仅会删除空目录,如果该目录下有其他文件则不会被删除,除非你把目录下其他文件都删除
  • file:如果不确定某个文件的类型,可以使用该命令file my_file查看文件类型
  • cat:查看文件,例如,cat xxx.log 可以查看该文件的所有内容
  • more:查看文件,可以通过空格键一直看下一页,较cat
  • less:和more差不多,一次显示一屏文本
  • tail:显示文件最后几行的内容,默认情况下显示最后10行
  • head:显示文件的开头那些行的内容,默认情况下显示前10行

7、探查进程

Unix风格的ps命令参数

参数描述用法
-A显示所有进程ps -A
-N显示与指定参数不符的所有进程
-a显示除控制进程和无终端进程外的所有进程
-d显示除控制进程外的所有进程
-e显示所有进程
-C cmdlist显示包含在cmdlist列表中的进程
-G grplist显示组ID在grplist列表中的进程
-U userlist显示属主的用户ID在userlist列表中的进程
-g grplist显示会话或组ID在grplist列表中的进程
-p pidlist显示PID在pidlist列表中的进程
-s sesslist显示会话ID在sesslist列表中的进程
-t ttylist显示终端ID在ttylist列表中的进程
-u userlist显示有效用户ID在userlist列表中的进程
-F显示更多额外输出
-O format显示默认的输出列以及format列表指定的特定列
-M显示进程的安全信息
-c显示进程的额外调度器信息
-f显示完整格式的输出
-j显示任务信息
-l显示长列表
-o format仅显示由format指定的列
-y不要显示进程(process flag,表明进程状态的标记)
-Z显示安全标签(security context)信息
-H用层级格式来显示进程(树状,用来显示父进程)
-n namelist定义了WCHAN列显示的值
-w采用宽输出模式,不限宽度显示
-L显示进程中的线程
-V显示ps命令版本号

8、监测程序

我们平时会用top命令来实时监测进程,会得到如下图所示界面

image.png

  • 第一行:显示了当前时间、系统得运行时间、登录得用户数以及系统的平均负载
  • 第二行:显示了进程概要信息,top命令的输出中将进程叫做任务(task):有多少进程处在运行、休眠、停止或是僵化状态(僵化状态是指进程完成了,但父进程没有响应)
  • 第三行:显示了CPU的概要信息
  • 第四行:显示了系统的物理内存,总共有多少内存,当前用了多少,还有多少空闲
  • 第五行:显示系统交换空间的存储占用状态
  • 第六行:白色背景行
    • PID:进程的ID
    • USER:进程属主的名字
    • PR:进程的优先级
    • NI:进程的谦让度
    • VIRT:进程占用的虚拟内存总量
    • RES:进程占用的物理内存
    • SHR:进程和其他进程共享的内存总量
    • S:进程的状态(D代表可终端的休眠状态,R代表在运行状态,S代表休眠状态,T代表跟踪状态或停止状态,Z代表僵化状态)
    • %CPU:进程使用的CPU时间比例
    • %MEM:进程使用的内存可占用内存的比例
    • TIME+:自进程启动到目前为止的CPU时间总量
    • COMMAND:进程所对应的命令行名称,也就是启动的程序名

9、Linux账户和组

9.1、账户查看

Linux系统管理的日常工作之一就是管理系统的账号,我们知道我们可以创建不同的用户和不同的组来分配对系统的不同权限,我们使用如下命令可以查看到当前操作系统中所有的账号信息

cat /etc/passwd

image.png

可以看到我们熟悉的root字段排在第一行,后面以“:”分割了很多其他的符合,这些分别是什么意思呢?我们从左至右按“:”分割为7列依次说明。

  • 第1列、账户名称:第一列的root其实就是系统管理员的账号
  • 第2列、密码:这里只显示了个x,老早以前这里放的是明文密码,但是有点危险,后来用x代替,实际的密码存储在/etc/shadow中
  • 第3列、UID:使用者识别码
  • 第4列、GID:这个与/etc/group有关,用户所属组ID
  • 第5列、使用者信息说明栏
  • 第6列、主文件夹:这是使用者的主文件夹
  • 第7列、Shell:登录时默认的bash

9.2、密码查看

我们再看下密码的相关规则,按照上面分析的逻辑一起看下这里的解释,同样按照“:”分割,我们可以得到9列数据

head -n 4 /etc/shadow

image.png

  • 第1列:账号名称
  • 第2列:密码:这个字段内的数据就是真正的密码,只不过是经过编码的密码
  • 第3列:最近更改密码的日期,这个字段记录了哪天改了密码,Linux时间是以1970年1月1日作为1而累加的日期,1971年1月1日则为366了。
  • 第4列:密码不可被更改的天数,如果是0的话,表示密码可以随时改动,如果是20的话则表示20天内都无法改变这个密码
  • 第5列:密码需要重新变更的天数,这个字段可以指定在最近一次更改密码后多次需要再次变更密码
  • 第6列:密码需要变更期限前的警告天数,会提醒用户再过n天你得密码就要过期了,请尽快重新设置你得密码等提示
  • 第7列:密码过期后的账号宽限时间,即使密码过期了也可以正常登录使用,但会一直提醒修改密码
  • 第8列:账号失效日期,当你设置了失效日期后该账户到期后将不能再被使用,不论你的密码是否有过期。
  • 第9列:保留项

9.3、添加新用户

我们主要使用useradd来添加系统新用户,可以一次性创建新用户账户及设置用户HOME目录结构,可以使用加-D选项的useradd命令查看Linux中的默认值

[root@localhost ~]# /usr/sbin/useradd -D
GROUP=100       #新用户会被添加到GID为100的公共组中
HOME=/home      #新用户的HOME目录将会位于/home/loginname
INACTIVE=-1     #新用户账户密码过期后不会被禁用
EXPIRE=         #新用户未设置过期日期
SHELL=/bin/bash    #新用户将bash shell作为默认shell
SKEL=/etc/skel     #系统会将/etc/skel目录下的内容复制到用户的HOME目录下
CREATE_MAIL_SPOOL=yes   #系统为该用户账户在mail目录下创建一个用于接收邮件的文件

useradd命令行参数解释如下

参数描述
-c comment给用户添加备注
-d home_dir为主目录指定一个名字
-e expire_date用YYYY-MM-DD格式指定一个账户过期日期
-f inactive_days指定账户密码过期多少天后被禁用;0表示密码一过期就禁用,1表示禁用这个功能
-g initial_group指定用户登陆组的GID或组名
-G group ...指定用户除登录之外所属的一个或多个附加组
-k必须和-m一起使用,将/etc/skel目录的内容复制到用户的HOME目录
-m创建用户的HOME目录
-M不创建用户的HOME目录
-n创建一个与用户登录名同名的新组
-r创建系统账户
-p为用户账户指定默认密码
-s指定默认的登录shell
-u为账户指定唯一的UID

9.4、删除用户

使用userdel命令删除用户,默认情况下,该命令只会删除/etc/passwd文件中的用户信息,而不会删除系统中属于该账户的任何文件。

/usr/sbin/userdel -r test

9.5、修改用户

命令描述
usermod修改用户账户的字段,还可以指定主要组以及附加组的所属关系
passwd修改已有用户的密码
chpasswd从文件中读取登录名密码对,并更新密码
chage修改密码的过期日期
chfn修改用户账户的备注信息
chsh修改用户账户的默认登录shell
9.5.1、usermod
  • -l修改用户账户的登录名
  • -L锁定账户,使用户无法登录
  • -p修改账户的密码
  • -U解除锁定,使能正常登录

9.6、使用Linux组

用户账户在控制单个用户安全性很好用,但涉及共享资源时,一组用户就显得更为方便;每个组都有唯一的GID,在系统上这是唯一的数值。

9.6.1、创建新租

我们使用groupadd在系统上创建新组

# 如下命令展示了新建一个shared的组
/usr/sbin/groupadd shared

# 我们可以使用usermod来修改一个用户所属组
usermod -G shared gaoyang

# 我们也可以修改组名,组内的用户关系不会变,因为是跟着组ID关联的
groupmod -n sharing shared

通过tail /etc/group 命令查看可以看到shared组里面已经有2个用户了

image.png

10、编写基本脚本

shell可以让你把多个命令串起来一次执行完成

10.1、使用多命令

在Linux的命令行窗口中可以一次执行多个命令,只需要用“;”分割命令即可。如下所示我们使用date;who俩个命令显示了当前日期和谁登录了系统上。这种方式只要字符不超过255就行。

[root@localhost ~]# date;who

image.png

10.2、创建shell脚本

在创建shell脚本时,必须在第一行指定要使用的shell,其格式为:

#!/bin/bash

10.3、显示消息

有时候我们希望在执行脚本时输出一些文字信息,这时我们可以使用echo命令

#!/bin/bash
echo the time and date are:
date

10.4、使用变量

运行shell脚本时可能需要用到一些变量

10.4.1、环境变量

Linux维护了一组环境变量,我们可以使用set查看当前环境变量列表

image.png

10.4.2、用户变量

除了环境变量,shell脚本允许用户定义和使用自己的变量。用户变量可以是任何由字母、数字、下划线组成的文本字符串,长度不超过20个且区分大小写。所以Var1和var1不是同一个变量。一个变量也可以赋值给另一个变量。

#!/bin/bash
days=10
guest="gaoyang"
echo "$guest checked in $days days ago"
guest2=$guest
echo "guest2 is $guest"

image.png

10.4.3、命令替换

我们在编写shell脚本时也可以从命令输出中提取信息,并赋值给变量,有两种方式可以实现

  • 反引号字符(`)
  • $()格式
#!/bin/bash
testing1=`date`
testing2=$(date)
echo "the testing1 and testing2 are:" $testing1 $testing2

11、使用结构化命令

11.1、if-then语句

在bash shell中if语句会执行if后面的那个命令。如果该命令的退出状态码是0,位于then部分的命令就会被执行。如果该命令的退出状态码是其他值,then部分的命令就不会被执行,bash shell会继续执行脚本中下一个命令。fi语句用来表示if-then语句到此结束。

if command
then
    commands
fi

参考一个简单的案例

#!/bin/bash
if pwd
then
    echo "it worked"
fi
echo "we are outside the if then"

执行上述脚本会打印 "it worked" 和 "we are outside the if then" 两句话

11.2、if-then-else语句

使用if-then-else语句可以在if条件不满足时执行另一个分支的命令

if command
then
    commands
else
    commands
fi

参考一个简单的案例,这里的IamNotCommand是一个不存在的命令

#!/bin/bash
if IamNotCommand
then
    echo "it worked"
else
    echo "this is another branch"
fi
echo "we are outside the if then"

11.3、嵌套if

if-then其中可以嵌套if参考以下案例

#!/bin/bash
testuser=NoSuchUser
if grep $testuser /etc/passwd
then
    echo "the user $testuser exists on this system"
else
    echo "the user $testuser does not exists on this system"
    if ls -d /home/$testuser
    then
        echo "however,$testuser has a directory"
    fi
fi
echo "we are outside the if then"

当然我们也可以使用else部分的另一种形式:elif。这样就不用再书写多个if-then语句了

if command1
then
    commands
elif command2
then
    more commands
fi

案例如下:

#!/bin/bash
testuser=NoSuchUser
if grep $testuser /etc/passwd
then
    echo "the user $testuser exists on this system"
elif ls -d /home/$testuser
then
    echo "the user $testuser does not exists on this system"
    echo "however,$testuser has a directory"
else
    echo "the user $testuser does not exists on this system"
    echo "and,$testuser dose not have a directory"
fi
echo "we are outside the if then"

我们可以将多个elif语句串起来,形成一个大的if-then-elif嵌套组合

if command1
then
    command set 1
elif command2
then
    command set 2
elif command3
then
    command set 3
elif command4
then
    command set 4
fi

11.4、复合条件测试

if-then语句允许你使用布尔逻辑来组合测试。有两种布尔运算符可用:

  • [condition1] && [condition2]:使用AND布尔运算符来组合两个条件,都为TRUE则成立
  • [condition1] || [condition2]:使用OR布尔运算符来组合两个条件,任意条件为TRUE则成立

11.5、case命令

有时候写多个if-then会很麻烦,我们可以使用case来简化脚本

case variable in
pattern1 | pattern2) commands1;;
pattern3) commands2;;
*) default commands;;
esac

案例如下:

#!/bin/bash
case $USER in
rich | barbara)
    echo "welcome, $USER"
    echo "please enjoy your visit";;
testing)
    echo "special testing account";;
jessica)
    echo "do not forget to log off when you're done";;
*)
    echo "sorry,you are not allowed here";;
esac

12、更多的结构化命令

12.1、for命令

当你需要重复执行一组命令直到达到某个特定条件,这时候我们可以选择for命令,基本格式如下:

for var in list
do 
    commands
done

for命令遍历值列表,我们使用test来接收循环的参数,最后一次迭代完成test的值就是最后一次遍历的值,案例如下:

#!/bin/bash
for test in gaoyang chenxi qinyawen humaoan
do
    echo the next ops is $test
done
echo "the last state we visited was $test"

或者从变量读取值

#!/bin/bash
list="gaoyang chenxi qinyawen humaoan"
list=$list" funu"
for name in $list
do
    echo the next ops is $name
done
echo "the last state we visited was $test"

12.2、while命令

while命令的格式是

while test command
do
    other commands
done

while命令的关键字在于test command的退出状态码必须随着循环中运行的命令而改变。如果退出状态码不改变,循环就一直不停的进行下去。

#!/bin/bash
var1=10
while [ $val1 -gt 0 ]
do
    echo $var1
    var1=$[ $var1 - 1 ]
done

12.3、until命令

until命令要求你指定一个通常返回非零退出状态码的测试命令。只有测试命令的退出状态码不为0,bash shell才会执行循环中列出的命令,一旦测试命令返回了退出状态码0,循环就结束了。

until test commands
do
    other commands
done

案例如下:

#!/bin/bash
var1=10
until [ $val1 -eq 0 ]
do
    echo $var1
    var1=$[ $var1 - 25 ]
done

12.4、嵌套循环

#!/bin/bash
for ((a=1;a<=3;a++))
do
    echo "Starting loog $a:"
    for ((b=1;b<=3;b++))
    do
        echo "inside loop:$b"
    done
done

12.4、控制循环

12.4.1、break
#!/bin/bash
for var1 in 1 2 3 4 5 6 7 8 9 10
do
    if [$var1 -eq 5]
    then
        break
    fi
    echo "iteration number:$var1"
done
echo "the for loop is completed"
12.4.2、continue
#!/bin/bash
for ((var1=1;var1 < 15; var++))
do
    if [$var1 -eq 5] && [$var1 -lt 10]
    then
        continue
    fi
    echo "iteration number:$var1"
done

13、处理用户输入

13.1、命令行参数

向shell脚本传递数据的最基本方法是使用命令行参数,命令行参数允许在运行脚本时向命令行添加数据,在脚本中我们可以通过11,2来依次获取命令行参数,$0获取的是脚本的名字

[root@localhost scripts]# sh param.sh 10 30

案例如下:

#!/bin/bash
total=$[$1 * $2]
echo the first paramter is $1
echo the second paramter is $2
echo the total value is $total

13.2、查找选项

#!/bin/bash
echo
while [ -n "$1"]
do
    case "$1" in
        -a) echo "found the -a option";;
        -b) echo "found the -b option";;
        -c) echo "found the -c option";;
        -*) echo "$1 is not an option";;
    esac
    shift
done

13.3、获得用户输入

read命令从标准输入或另一个文件描述符中接收输入

#!/bin/bash
echo -n "Enter your name:"
read name
echo "hello $name,welcome to my program."

或者是下面这种形式

#!/bin/bash
read -p "Enter your name:"
echo
echo hello $REPLY,welcome to my program.

当然我们也可限制用户输入的时间,防止脚本一直苦等,-t选项指定了read命令等待输入的秒数。当计时器过期后,read命令会返回一个非零退出状态码。

#!/bin/bash
if read -t 5 -p "Enter your name:" name
then
    echo "hello $name,welcome to my program."
else
    echo
    echo "sorry,too slow! "
fi

有时我们也希望可以采取隐藏方式读取,例如要求输入密码等信息时

#!/bin/bash
read -s -p "enter your password:" pass
echo
echo "is your password really $pass ?"

14、控制脚本