Shell是系统的用户界面,提供了用户内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行。

①Shell是一个命令解释器,它解释由用户输入的命令并且把它们送到内核。

②Shell是一个解释型的程序设计语言。

以下对linux进程管理的作用描述正确的有(ABC)

A.判断服务器的健康状态

B.查看系统中所有的进程

C.杀死进程

D.查看服务器CPU信息

简单命令

  1. date:打印或设置系统日期和时间。

  2. who:查看系统中所有已登录用户的情况。

  3. passwd:修改用户密码。

  4. logout, login:登录shell的登录和注销命令。

  5. pwd:打印工作路径。

  6. more, less, head,tail:显示或部分显示文件内容。

  7. lp/lpstat/cancel, lpr/lpq/lprm:打印文件。

  8. chmod u+x:更改文件权限。

  9. rm -fr dir:删除非空目录。

  10. cp -R dir:拷贝目录。

  11. fg jobid:将一个后台进程放到前台。

    • 使用Ctrl+z可以将前台进程挂起(suspend),然后可以使用bgjobid命令将其放到后台运行。
    • 使用job&可以直接让作业在后台运行。
  12. kill:删除执行中的程序或工作。

  13. ps:列出当前运行的进程。

    • 不带参数的ps命令运行时, 显示该用户当前活动进程的基本信息
    • ps命令的常用任选项 -e (或-a) 显示系统中所有活动进程的信息.
    • -f 显示该进程的所有信息.

输出重定向

标准输入: 键盘 fd = 0

标准输出: 荧光屏 fd = 1

标准错误输出:荧光屏 fd = 2

command > filename 进程输出覆盖文件 filename

command >> filename 进程输出追加到文件filename后面, 不覆盖filename

例如:

把文件myfile的内容输出到标准输出文件—-荧光屏上

1
$ cat myfile

把文件myfile的内容输出到文件newfile中(标准输出已被重新定向到newfile). 其结果相当于拷贝文件.

1
$ cat myfile > newfile

把abc添加到xyz已有内容后面, 而不是覆盖xyz

1
$ cat abc >> xyz

应用举例:
① 按字母顺序显示当前系统中所有已登录的用户:

把当前登录用户的名单保存在temp1中

1
$ who > temp1

把排序后的名单保存在temp2中

1
$ sort temp1 > temp2 

逐屏显示排好序的用户名单

1
$ more temp2 

删除不用的临时文件

1
$ rm temp1 temp2 

② 记录长时间运行程序的日志:

把排序后的名单累加(而不是覆盖)到文件temp2中。

1
$ sort temp1 >> temp2 

输入重定向

command < filename
进程的输入来自文件filename, 例如:

cat进程的输入不是来自命令行参数,而是来自重定向文件abc,cat进程的输出送到标准输出荧光屏上:

1
2
3
4
5
$ cat < abc
aaaaaaaaaaaaaaa
bbbbbbbb
cccccccccccccccccc
$

常见输入输出重定向方式

命令 输入 输出 效果
cat 键盘 屏幕 将键盘输入显示在屏幕上
cat file1 file1 屏幕 file1的内容显示在屏幕上
cat file1 > file2 file1 file2 file1的内容写入file2中
cat > file2 键盘 file2 键盘输入的内容写入file2
cat < file1 file1 屏幕 file1的内容显示在屏幕上
cat < file1 > file2 file1 file2 file1的内容写入file2中

command 2> filename ( 2和>之间没有空格 ),进程运行中的错误信息重定向到文件filename, 例如:

如果命令运行正常, 则把结果(连接file1和file2)存入file3中;如果出现错误, 则把错误信息存放到errfile中。

1
$ cat file1 file2 > file3 2> errfile

管道

管道用于连接两个命令, 它把前一个命令的标准输出重定向给后一个命令作为标准输入, 其格式为:
command1 | command2
对command1来说标准输出被重新定向到管道, 对command2来说标准输入也被重新定向为管道.

例1:按字母顺序显示当前系统中所有已登录的用户。

1
$ who | sort | more

例2:

查看系统当前有几个用户在上机使用系统.(wc - 统计文件的字节数、字数、行数)

1
$ who | wc –l

把文件myfile按标准打印格式处理后, 送到打印机打印出来(原文件myfile并未作任何修改)。lp - 打印文件或修改排队的打印任务。pr - 将文本文件转换成适合打印的格式。

1
$ pr myfile | lp

在包含所有用户名单的文件user_list中, 查找包含student的行, 并把结果排序后存放在文件stu_list中. (管道和输出重定向混合使用)。grep - 强大的文本搜索工具。

1
$ grep student user_list | sort > stu_list

命令形式

单条命令

这是最常用命令形式, 本命令执行完成后出现shell提示符, 再接收下一条键盘命令.

1
$ cat file1

多条命令

第一条命令执行完成后, (无停顿)再执行第二条命令, 如此下去. 运行功能和效果与在键盘上逐条输入命令并运行是完全一样的, 其主要目的是提高键盘命令输入效率。

1
$ pwd; who; date

复合命令

管道前后的命令任意组合、同时运行, 形成功能更强大灵活的复合命令.

1
$ ps –e | grep student2

括号内的命令任意组合、顺序执行,且由一个子shell来单独控制运行, 相当于一个小的功能程序. 方便灵活, 运行效率高。

1
$ (ls ; cat file3 ; pwd) > run_log

后台命令

1
2
3
$ ls –lR > file_list &
[1] 7981
$

普通命令行的行尾加上&符号,就表示该命令在后台执行。

[1]: 当前shell的后台作业(进程)序号

7981: 当前这个后台进程(ls进程)的进程号(PID)。
Shell 启动该后台进程后不再等待该进程结束,立即开始接受新的键盘命令——多进程并发, 数量不限, 充分利用系统资源。

环境变量

系统的基本环境变量放在/etc/profile中, 用户环境变量放在用户主目录下的.profile文件中, 用户shell启动时, 先执行/etc/profile, 再执行用户主目录下的.profile。环境变量可在shell运行时动态修改。

常用的shell环境变量及实例:

HOME=/usr/computer/student6 用户主目录, 注册时的初始目录

PATH=/bin:/usr/bin:$HOME/bin:./ 键盘命令的搜索路径

SHELL=/bin/sh 用户的初始shell的路径名称

TERM=vt100 当前所用的终端类型

PS1=$ shell的主提示符

IFS= 域分隔符, 通常为空白符, 用来分隔命令行各个域

echo

echo命令的基本功能就是在标准输出上显示后面的字符串,或变量的值。当字符串中带空白符或其它控制字符时,用引号将其括起来。例如:

1
2
3
4
5
6
7
8
$ echo 12345
12345
$ echo "department computer"
department computer
$ echo "My home directory is: $HOME"
My home directory is: /usr/teacher/david
$ echo –n "Input your choice (y/n) [ ]\b\b"
Input your choice (y/n) [ _ ]

使用echo命令时,输出会自动换行,而使用echo -n命令时,输出不会换行。

系统变量

常用系统变量:

$0 当前shell程序的名字

$1 ~ $9 命令行上的第一到第九个参数

$# 命令行上的参数个数

$* 命令行上的所有参数

$@ 分别用双引号引用命令行上的所有参数

$$ 当前进程的进程标识号(PID)

$? 上一条命令的退出状态

$! 最后一个后台进程的进程标识号

系统变量只能引用不能修改!

系统变量应用举例:

1
2
3
4
5
6
7
8
9
$ echo aa bb cc dd $$
aa bb cc dd 2391
$ cat file1 file2 > file3 2> errlog
$ echo $? (非0表示命令运行失败, 错误信息在 errlog 文件中)
$ echo
(空行, 即echo输出串尾隐含的换行符)
$ echo This is a test. (单词间多个空格)
This is a test.
$ echo "This is a test." (用引号包括时结果如何?)

局部变量(用户变量)

局部变量是由用户根据需要任意创建的. 变量名通常由一个字母后跟零个到多个字母、数字或下划线组成。引用变量的值时,在变量名前面加上$符号. 例如:

1
2
3
4
5
6
$ AA=123 				定义变量AA
$ echo $AA 引用变量AA的值
123 (变量AA的值)
$ B="this is a string" 定义变量B, (字符串中有空格时用引号)
$ echo $B 引用变量B的值
this is a string (变量B的值)

单引号、双引号、反撇号和花括号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ a="he is a student"
$ echo "She said: $a"
She said: he is a student echo执行时,替换了变量$a的值
$ b='The value of a is $a'
$ echo $b
The value of a is $a echo执行时,未替换了变量$a的值

shell规定单引号禁止变量替换, 元字符$和*等保持其符号本身; 而双引号允许元字符变量替换.

$ c="The value of a is $a"
$ echo $c
The value of a is he is a student

$ a=date
$ echo $a
date (变量a的值是字符串date)
$ b=`date` (反撇号中的字符串作为命令名)
$ echo $b
Sat Feb 1 16:28:19 Beijing 2003
(变量b的值是反撇号中命令的执行结果)

$ c="There is a teach"
$ echo "$cer reading room"
reading room (未定义变量cer, 其值用空串替代)
$ echo "${c}er reading room"
There is a teacher reading room
(花括号将变量名和后面的字符串区分开)

shell编程

shell 编程的基本过程主要包含以下三步:

  1. 建立 shell 文件
    包含任意多行操作系统命令或shell命令的文本文件;
  2. 赋予shell文件执行权限
    用chmod命令修改权限;
  3. 执行shell文件
    直接在命令行上调用该shell程序.

示例:

1
2
3
4
5
6
7
8
9
10
11
12
1. 建立shell文件 (可用任何建立文本文件的方法):
$ cat prog1
who | grep $1
2. 赋予执行权限: (初始文本文件无执行权限)
$ chmod 740 prog1
3. 执行该shell程序
$ prog1 student5
prog1: not found
(shell在标准搜索目录中找不到prog1命令)
4. 指定路径或修改环境变量PATH后执行shell程序
$ ./prog1 student5
student5 tty06 Feb 8 09:12

shell 程序和语句

shell 程序由零至多条shell语句构成. shell语句包括三大类: 功能性语句、结构性语句和说明性语句。
说明性语句(注释行):

以#号开始到行尾的部分,不被解释执行。

功能性语句:

任意的操作系统命令、shell内部命令、自编程序、其它shell程序名等。

结构性语句:

条件测试语句、多路分支语句、循环语句、循环控制语句等。

read命令
read从标准输入读入一行, 并赋值给后面的变量, 其语法为:

. read var

把读入的数据全部赋给var

. read var1 var2 var3

把读入行中的第一个参数赋给var1, 第二个参数赋给 var2, ……,把其余所有的参数赋给最后一个变量.

如果执行read语句时标准输入无数据, 则程序在此停留等侯, 直到数据的到来或被终止运行.

read应用实例(命令行执行)
read 读取标准输入(键盘), 输入的内容赋给后面的变量.

1
2
3
4
$ read name age
yilan 23 #从键盘输入的内容
$ echo "student $name is $age years old"
student yilan is 23 years old #屏幕显示的内容

read应用实例(shell脚本程序)

1
2
3
4
5
6
7
8
9
10
11
12
#example1 for read
echo -n "Input your name: "
read username
echo "Your name is $username"

#example2 for read
echo –n "Input date with format yyyy mm dd: "
read year month day
echo "Today is $year/$month/$day, right?"
echo -n "Press any key to confirm and continue"
read answer
echo "I know the date, bye!"

expr 命令

算术运算命令expr主要用于进行简单的整数运算,包括加(+)、减(-)、
乘(\*)、整除(/)和求模(%)等操作。例如:

1
2
3
4
5
6
7
8
9
10
$ expr 12 + 5 \* 3		#反斜线去掉*号的元字符含义
27
$ expr 3 - 8 / 2
-1
$ expr 25 % 4
1
$ num=9
$ sum=`expr $num \* 6` #反撇号引用命令的运行结果
$ echo $sum
54

条件语句

语法结构:

1
2
3
4
5
6
7
8
if 表达式
then 命令表
fi

if 表达式
then 命令表1
else 命令表2
fi

if语句应用实例

shell程序prog2, 测试命令行参数是否为一个已存在的文件或目录。 用法为:prog2 file
prog2脚本内容如下:

1
2
3
4
5
6
7
8
9
#The statement of if…then…fi (注释语句)
if [ -f $1 ] (测试命令行第一个参数是否为文件)
then
echo "File $1 exists" (引用变量值)
fi
if [ -d $HOME/$1 ] (测试参数是否为目录)
then
echo "File $1 is a directory" (引用变量值)
fi

应用实例: shell程序prog3, 用法为: prog3 file
prog3的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
#The statement of if…then…else…fi
if [ -d $1 ]
then
echo "$1 is a directory"
exit (立即退出当前的shell程序)
else
if [ -f $1 ]
then
echo "$1 is a common file"
else
echo "unknown"
fi
fi

测试语句

test语句可测试三种对象:字符串,整数,文件属性
每种测试对象都有若干测试操作符,例如:

1
test "$answer" = "yes"

变量answer的值是否为字符串yes

1
test $num –eq 18

变量num的值是否为整数18

1
test -d tmp

测试tmp是否为一个目录名

test命令的应用:
test命令测试的条件成立时, 命令返回值为真(0),否则返回值为假(非0).
用法一.

1
2
test $name -eq $1 
echo $?

用法二.

1
2
3
4
if test -f $filename
then
……
fi

用方括号替代test语句,通常简写为: if [ -f $filename ]

循环语句

当循环次数已知或确定时, 使用for循环语句来多次执行一
条或一组命令. 循环体由语句括号do和done来限定。 格式为:

1
2
3
4
for 变量名 in 单词表
do
命令表
done

变量依次取单词表中的各个单词, 每取一次单词, 就执行一次循环体中的命令. 循环次数由单词表中的单词数确定. 命令表中的命令可以是一条, 也可以是由分号或换行符分开的多条。如果单词表是命令行上的所有位置参数时, 可以在for语句中省略 “in 单词表” 部分。

1
2
3
4
while 命令或表达式
do
命令表
done

while语句首先测试其后的命令或表达式的值,如果为真,就执行一次循环体中的命令,然后再测试该命令或表达式的值,执行循环体,直到该命令或表达式为假时退出循环。while语句的退出状态为“命令表”中被执行的最后一条命令的退出状态。

shell示例

第一题必须掌握,二三题看个人吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/sh
# Put line numbers on all lines of a file
if [ $# -ne 1 ]
then
echo "Usage: $0 filename " >&2
exit 1
fi
count=1 # Initialize count
cat $1 | while read line
# Input is coming from file on command line
do
echo $count $line
count=`expr $count + 1`
done > tmp$$ # Output is going to a temporary file
mv tmp$$ $1

这段代码是一个shell脚本,其功能是为一个文件的每一行添加行号。首先,#!/bin/sh指定了脚本的解释器为/bin/sh。然后,脚本使用了一个条件判断语句,if [ $# -ne 1 ],判断脚本的参数个数是否为1。-ne是一个条件测试运算符,用于比较两个数是否不相等$#是一个特殊变量,表示传递给脚本的参数个数。如果参数个数不等于1,则执行条件判断中的代码块。在条件判断代码块中,echo "Usage: $0 filename" >&2用于输出错误信息到标准错误输出$0是一个特殊变量,表示脚本的名称。>&2将输出重定向到标准错误输出。然后使用exit 1退出脚本,返回状态码1表示发生了错误。如果参数个数为1,则继续执行后面的代码。count=1初始化一个变量count,用于保存行号。接下来使用cat $1 | while read line语句,从命令行参数中的文件中逐行读取内容,并将每行内容赋值给变量line$1:表示脚本的第一个参数,即文件名。cat $1:使用cat命令将文件内容输出到标准输出。在循环中,使用echo $count $line输出行号和当前行的内容。echo $count $line会在行号和内容之间输出一个空格。然后,使用count=expr $count + 1将行号加1,并将结果赋值给变量count。循环结束后,使用done > tmp$$将循环中的输出重定向到一个临时文件tmp$$中。$$是一个特殊变量,表示当前脚本的进程ID。最后,使用mv tmp$$ $1将临时文件tmp$$重命名为原始文件名$1,覆盖原始文件,实现了为文件的每一行添加行号的功能。


编写程序列出当前登录用户的账号,并在有新用户登录时显示新用户的登录信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
# List current logged-in users and display new login information

# Get the initial list of logged-in users
users=$(who | awk '{print $1}')

# Continuously check for new logins
while true; do
# Get the updated list of logged-in users
new_users=$(who | awk '{print $1}')

# Check for new logins
for user in $new_users; do
if [[ ! $users =~ $user ]]; then
echo "New login: $user"
fi
done

# Update the list of logged-in users
users=$new_users

# Sleep for 1 second before checking again
sleep 3
done

使用who命令获取当前登录用户的信息,并使用awk命令提取每行的第一个字段(即用户名),将结果赋值给变量users,这是初始登录用户列表。if [[ ! $users =~ $user ]]; then:在循环中,检查当前用户是否为新用户。$users是之前保存的登录用户列表,$user是当前循环中的用户。

  • [[ ... ]]:这是bash中的条件表达式,用于进行条件判断。
  • !:这是逻辑取反运算符,表示对后面条件的结果进行取反。
  • =~:这是一个正则表达式匹配运算符,用于判断左侧的字符串是否匹配右侧的正则表达式。

编写程序列出指定目录下文件大小大于指定大小的文件名及其完整信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/bin/bash
# List files in a directory larger than a specified size

# Check for correct number of arguments
if [[ $# -ne 2 ]]; then
echo "Usage: $0 directory size"
exit 1
fi

# Get the arguments
dir=$1
size=$2

# Find and list the files larger than the specified size
find $dir -type f -size +${size}k -exec ls -lh {} \;
  • if [[ $# -ne 2 ]]; then:这是一个条件判断语句,用于检查命令行参数的数量是否为2。
  • echo "Usage: $0 directory size":如果命令行参数数量不为2,则输出使用说明。

find $dir -type f -size +${size}k -exec ls -lh {} \;:使用find命令查找目录$dir下的文件,其中:

  • -type f:限定查找的对象为文件。

  • -size +${size}k:限定文件大小大于指定的大小${size}(单位为k)。

  • -exec ls -lh {} \;:对于每个符合条件的文件,执行ls -lh命令来列出文件的详细信息。

  • {}:在find命令中,{}表示找到的每个文件的占位符。find命令会将找到的每个文件依次替换为{},从而允许对这些文件执行特定的操作。

  • \;:在find命令中,\;表示一个分隔符,用于表示-exec选项的结束。它告诉find命令在每个被替换的文件后加上分号,以标记执行命令的结束。