前言

这两天我的笔记本上的键盘坏掉了,QWER,UIOP这几个按键用不了了。

解决方案1:烘干

我不知道是什么原因,可能是进水了吧。刚开始我把键盘拆下来用电吹风吹了一阵子,重新安装到笔记本上,这几个按键倒是能用,但是这几个按键按一次,就会打出好多字。
所以我想,那应该是没有干透,所以我又拆下键盘,放到烤箱里,用90℃左右的温度烘烤,到了第二天早上的时候我把键盘拆下来,重新安装回去,这几个按键又好了。

方案2:买个原装键盘安装上去

但是好景不长,等下午我关机之后,重新开机,这几个按键又无法使用了。
没办法,我只能网上重新买一个笔记本的原装键盘安装上去了。

不过,等待快递需要时间,在这个时间内我探索了如下一些使用虚拟键盘的方法。

使用win10自带的触摸键盘

win10进入系统之后如何打开触摸键盘:
图片
win10开机时如何使用虚拟键盘:
不过触摸键盘使用起来不是很方便,我的电脑比较老,没有触摸屏的功能。这种情况下,使用虚拟键盘的话,需要用鼠标来点击各个按键,打一个字的话需要好长的时间。
应急使用到时可以。

使用手机作为电脑的键盘

这类软件有一些,良莠不齐。经过我这两天的测试,可用的软件有如下几款。

remote mouse

官网:https://www.remotemouse.net/

  • 需要在电脑上安装电脑版的,
  • 在手机上安装手机版的
  • 将手机和电脑连接到同一Wi-Fi,即可使用手机来给电脑打字:

图片
电脑版界面:
图片
手机版界面:
图片
启动界面:
图片
连接该电脑之后,APP上的主界面是触控板功能,以及鼠标左键,鼠标中键,鼠标右键
再下方是工具栏,工具栏上有键盘开关,任务栏视图等功能。
图片

工具栏介绍

工具栏从左到右的功能为:音乐控制工具?(付费功能),任务栏切换工具(免费),网页工具(付费),键盘开关(免费),Fn按钮(付费),Ctrl按钮(付费)。
这里只介绍键盘和鼠标的功能,其他功能请自行尝试:

多媒体遥控器

付费功能
图片

程序遥控器

免费
点击上面的软件图标,可以把相应的软件切换到电脑前台
图片

电源选项

免费
图片

键盘

免费
图片

网页遥控器

付费功能
图片

数字与功能键盘

付费功能
图片

Ctrl bar

付费功能
图片

优点:

  • 切换电脑上的程序
  • 鼠标的功能,
  • 使用手机输入法,符合用户习惯
  • 提供电源控制功能

缺点:

数字键和功能键(esc,tab,insert,home,pgup,pgdn,delete,end,方向键)需要付费使用
shift,Ctrl,win,Alt键需要付费使用。

UnifiedRemote

官网:https://www.unifiedremote.com
电脑版:
https://www.unifiedremote.com/download
APP:
https://play.google.com/store/apps/details?id=com.Relmtech.Remote

安装过程省略
图片

功能介绍

Keyboard

图片
这个自带的键盘上有我们常用的shift,Ctrl,Caps Look,Alt,enter,esc,tab,甚至是win键。

调用手机输入法:

按左下边的键盘图标,可以调用手机自身的输入法。这样便于输入。

鼠标功能

点击鼠标图标即可使用图标功能,再点击一次图标即可关闭鼠标功能,这个鼠标的缺点是没有提供鼠标的左中右键,而是使用手式来实现鼠标的左中右键的功能。

Keyboard(Function)

图片
这个键盘上带有多个特殊字符的按键,方便写代码。

Numpd

图片
这个是数字键盘,输入数字和加减乘除比较方便。

图片
这个键盘带有方向键。

环境变量和局部变量

默认类型

创建的shell变量,默认为局部变量

内部命令export

局部变量转换为环境变量,例如:

1
export proto

局部变量和环境变量

  • shell启动的子进程继承环境变量,不继承局部变量
  • 子进程对环境变量的修改,不影响父进程中同名变量

(环境变量的设置,如PATH,CLASSPATH,LANG,如果必要的话放在~/.bashrc中或/etc/profile中)

系统的环境变量

创建

登录后系统自动创建一些环境变量影响应用程序运行

HOME

用户主目录的路径名

PATH

命令查找路径
与DOS/Windows不同的是,它不首先搜索当前目录
PATH=/bin:/usr/bin:/etc
PATH=.:/bin:/usr/bin:/etc 先搜索当前目录(危险!)
PATH=/bin:/usr/bin:/etc:. 后搜索当前目录(危险!)

TERM:终端类型

◆全屏幕操作的软件(如vi),使用它搜索终端库
(环境变量的赋值对某个应用程序,包括java虚拟机以及其他的系统软件,有什么影响,与这个AP的设计相关,需要查阅相关的手册)

相关命令set/env

内部命令set列出当前所有变量及其值以及函数定义

  • 包括环境变量和局部变量、函数定义
  • set | grep ^fname=

外部命令/bin/env列出环境变量及其值

read:读用户的输入

内部命令read:变量取值的另外一种方法
从标准输入读入一行内容赋值给变量
例:读取用户的输入,并使用输入的信息。

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost 替换、元字符和转义]# ls
variable.sh varSet+U.sh
[root@localhost 替换、元字符和转义]# read name
helloWorld!
[root@localhost 替换、元字符和转义]# echo $name
helloWorld!
[root@localhost 替换、元字符和转义]# read file
variable.sh
[root@localhost 替换、元字符和转义]# echo $file
variable.sh
[root@localhost 替换、元字符和转义]# ls -l $file
-rw-r--r--. 1 root root 75 6月 27 15:56 variable.sh
[root@localhost 替换、元字符和转义]#

脚本程序中的行编辑

假设应用程序myap运行时从myap.conf中读取配置参数

bash变量

存储的内容

  • 字符串(对于数字串来说,不是二进制形式)
  • 在执行过程中其内容可以被修改

变量名

  • 第一个字符必须为字母
  • 其余字符可以是字母,数字,下划线

变量的赋值和引用

赋值与引用

1
2
addr=20.1.1.254
ftp $addr

注意:
赋值作为单独一条命令,等号两侧不许多余空格
引用addr变量的方法:$addr${addr}

1
2
echo ${addr}A
echo $addrA

命令行中含有$符的变量引用,shell会先完成变量替换。

1
2
3
4
5
6
[root@localhost 替换、元字符和转义]# addr=20.1.1.254
[root@localhost 替换、元字符和转义]# echo ${addr}A
20.1.1.254A
[root@localhost 替换、元字符和转义]# echo $addrA

[root@localhost 替换、元字符和转义]#

赋值时,等号右侧字符串中含有特殊字符

1
2
unit="Beiyou University"
echo $unit
1
2
3
4
[root@localhost 替换、元字符和转义]# unit="Beiyou University"
[root@localhost 替换、元字符和转义]# echo $unit
Beiyou University
[root@localhost 替换、元字符和转义]#

变量的引用

如果引用未定义变量,则变量值为空字符串

1
2
3
echo Connect to $proto Network
proto=TCP/IP
echo Connect to $proto Network

上面的第一行引用了proto变量,不过该变量没有定义过,此时将替换为空字符串,
第3行的也引用了proto变量,不过由于该变量在第2行已经定义过了,将会替换为该变量的值。
运行效果:

1
2
3
4
5
6
7
8
[root@localhost 替换、元字符和转义]# cat variable.sh 
echo Connect to $proto Network
proto=TCP/IP
echo Connect to $proto Network
[root@localhost 替换、元字符和转义]# bash variable.sh
Connect to Network
Connect to TCP/IP Network
[root@localhost 替换、元字符和转义]#

shell内部开关

  • set -u:当引用一个未定义的变量时,产生一个错误
  • set +u:当引用一个未定义的变量时,认为是一个空串(默认情形)
  • set -x:执行命令前打印出shell替换后的命令及参数,为区别于正常的shell输出,前面冠以+号
  • set +x:取消上述设置

在上面的代码前面加上set -u

varSet+U.sh
1
2
3
4
set -u
echo Connect to $proto Network
proto=TCP/IP
echo Connect to $proto Network

得到varSet+U.sh,然后运行该脚本:

1
2
3
[root@localhost 替换、元字符和转义]# bash varSet+U.sh 
varSet+U.sh:行2: proto: 为绑定变量
[root@localhost 替换、元字符和转义]#

命令echo

语法与功能

1
echo arg1 arg2 arg3 ...

打印各命令行参数,每两个参数之间用一空格分开,最后打印换行符

不可打印字符(转义):

Linux需加选项-e,(不同UNIX间兼容性差)
echo支持C语言字符串常数描述格式的转义和\c

转义字符 功能
\c 打印完毕,不换行
\b 退格
\n 换行
\r 回车
\t 水平制表
\\ 反斜线
\nnn 八进制描述的字符ASCII码

示例

举例

1
2
3
4
echo Beijing   China
echo "Beijing China"
echo -e '\065'
echo -e "\\r$cnt \\c"
1
2
3
4
5
6
7
8
9
[root@localhost ~]# echo Beijing   China
Beijing China
[root@localhost ~]# echo "Beijing China"
Beijing China
[root@localhost ~]# echo -e '\065'
5
[root@localhost ~]# echo -e "\\r$cnt \\c"
[root@localhost ~]#
[root@localhost ~]#

命令printf

命令printf,用法与C函数printf类似,例如:

1
printf '\033[01;33mConnect to %s Network\n' $proto

图片

Linux 输出重定向与管道

程序的标准输入/输出
图片

程序示例

使用系统调用(原始I/O)

stda.c

stda.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <string.h>
#include <unistd.h>
int main(void) /* 使用原始I/O */
{
static char *str1 = "string1\n";
static char *str2 = "string2\n";
int i;
for (i = 0; i < 10; i++) {
// 写入1号文件,也就是标准输出
write(1, str1, strlen(str1));
// 写入2号文件,也就是标准错误输出
write(2, str2, strlen(str2));
}
}

使用C语言库函数(缓冲I/O)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>
/* FILE*类型的变量stdin,stdout和stderr */
int main(void) /* 使用缓冲I/O */
{
static char *str1 = "string1\n";
static char *str2 = "string2\n";
int i;
for (i = 0; i < 10; i++) {
// 打印到标准输出
printf("%s", str1); /*或:fprintf(stdout, "%s", str1);*/
// 打印到标准错误输出
fprintf(stderr, "%s", str2);
}
}

stdout输出重定向

重定向覆盖文件

1
> filename

将stdout重定向到文件filename,文件已存在则先清空(覆盖方式)

重定向追加到文件

1
>> filename

将stdout重定向追加到文件filename尾

stderr输出重定向

标准错误输出重定向到文件

将文件句柄2重定向到文件filename

1
2> filename

分离stdout与stderr的意义:有时候会把stdout作为程序的运行结果重定向到文件中,如果不分离的话,文件中会夹杂有错误输出,干扰我们想要的结果。

标准错误输出与标准输出相同

将文件句柄2重定向到文件描述符1指向的文件:

1
2>&1

使用其他文件句柄

允许对除0,1,2外其它文件句柄输入或输出重定向,例如:

1
./myap 5< a.txt 6> b.dat

那么,在运行myap这个程序的时候,

  • 5号文件则不需要打开,可以直接从5号文件中读取。也就是直接从a.txt中读取。
  • 可以直接往6号文件中输出,也就是会直接写到b.dat文件中。

虽然这种用法不常见,但是也是可以这样使用的。

输出重定向示例

重定向stdout到文件

将命令ls标准输出stdout定向到文件file.list中:

1
ls -l > file.list

重定向stderr到文件

将gcc命令的stderr重定向到文件try.err中

1
gcc try.c -o try 2> try.err

重定向stdout和strerr到不同文件

将try程序执行后的stdout和stderr分别重定向到不同的文件:

1
try > try.out 2>try.err

或者:

1
try 1> try.out 2>try.err
1
./stda 1> try.out 2>/dev/null

stdout和stderr均存入文件rpt:

1
./stda >rpt 2>&1

程序示例

stda.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <string.h>
#include <unistd.h>
int main(void) /* 使用原始I/O */
{
static char *str1 = "string1\n";
static char *str2 = "string2\n";
int i;
for (i = 0; i < 10; i++) {
//写入1号文件,也就是标准输出
write(1, str1, strlen(str1));
//写入2号文件,也就是标准错误输出
write(2, str2, strlen(str2));
}
}

编译,运行该程序:

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
[root@localhost shell的基本机制]# gcc stda.c -o stda
[root@localhost shell的基本机制]# ls |grep 'stda'
stda
stda.c
[root@localhost shell的基本机制]# ./stda
string1
string2
string1
string2
string1
string2
string1
string2
string1
string2
string1
string2
string1
string2
string1
string2
string1
string2
string1
string2
[root@localhost shell的基本机制]#

可以看到标准输出和标准错误输出交替输出到屏幕上。光从打印的结果是无法看出那条是标准输出,那条是标准错误输出。

重定向标准输出到文件

运行该程序,把标准输出重定向到文件中:

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost shell的基本机制]# ./stda >stda.out
string2
string2
string2
string2
string2
string2
string2
string2
string2
string2
[root@localhost shell的基本机制]#

此时,屏幕上输出的就只剩下标准错误输出。

标准输出和标准错误输出都重定向到文件中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@localhost shell的基本机制]# ./stda >stda.out 2>stda.err
[root@localhost shell的基本机制]# cat stda.out
string1
string1
string1
string1
string1
string1
string1
string1
string1
string1
[root@localhost shell的基本机制]# cat stda.err
string2
string2
string2
string2
string2
string2
string2
string2
string2
string2
[root@localhost shell的基本机制]#

或者,不省略标准输出的文件描述符:

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
[root@localhost shell的基本机制]# rm *.out *.err
rm:是否删除普通文件 "stda.out"?y
rm:是否删除普通文件 "stda.err"?y
[root@localhost shell的基本机制]# ./stda 1>stda.out 2>stda.err
[root@localhost shell的基本机制]# cat stda.out
string1
string1
string1
string1
string1
string1
string1
string1
string1
string1
[root@localhost shell的基本机制]# cat stda.err
string2
string2
string2
string2
string2
string2
string2
string2
string2
string2
[root@localhost shell的基本机制]#

输出重定向顺序不要颠倒

正确写法

1
./stda >rpt 2>&1

命令执行时,各文件句柄的指向过程:
图片

错误写法:

1
./stda 2>&1 >rpt

图片

管道

传递前一个命令的标准输出给后一个命令作为标准输出

前一命令的stdout作后一命令的stdin

1
ls -l | grep '^d'

管道如何传递前一个命令的标准错误输出给后一个命令

前一命令的stdout+stderr作为下一命令的stdin:

1
gcc try.c -o try 2>&1 | more

这样才能实现使用more逐屏查看。因为编译是输出的错误信息,很多都是标准错误输出,但是呢,管道是把前面的标准输出传递给后面的命令作为标准输入。对于前一个命令的标准错误输出,管道是不会传递的。
所以为了使得后面的命令能看到前一个命令的标准错误输出,可以把标准错误输出合并到标准输出。这样才会通过管道传递给后面的命令。

输入重定向(从数据文件中获取stdin)

1
< filename

从文件filename中获取stdin,例如: sort < telno.txt

输入重定向(从shell中获得stdin:允许替换)

1
<<word

从shell脚本文件获取数据直到再次遇到定界符word

1
2
3
4
5
6
7
8
9
10
11
[root@localhost ~]# cat << END
> 1
> 2
> 3
> 4
> END
1
2
3
4
[root@localhost ~]#

不加单引号的情况,可以使用$变量名的形式获取变量的值:

[root@localhost 文件管理和目录管理]# cat << END
> hello you home dir is $HOME
> END
hello you home dir is /root
[root@localhost 文件管理和目录管理]# 
1
2
3
4
5
6
7
[root@localhost 文件管理和目录管理]# cat << END
> now:`date`
> you home dir is:$HOME
> END
now:2021年 06月 26日 星期六 17:38:32 CST
you home dir is:/root
[root@localhost 文件管理和目录管理]#

定界符所界定内容加工处理(等同双引号处理):

  • 变量替换,命令替换
  • 不执行文件名生成

输入重定向(从shell中获得stdin:不许替换)

<<word从shell脚本程序获取数据直到再次遇到定界符,定界符两侧加单引号:不允许定界符之间的内容进行替换操作。

定界符加上单引号,禁止替换操作

[root@localhost 文件管理和目录管理]# cat << 'END'
> hello you home sir is $HOME
> END
hello you home sir is $HOME
[root@localhost 文件管理和目录管理]# 

输入重定向(从命令行获取信息作为标准输入)

1
<<<word

直接使用三个大于号后面的单词作为命令的输入。

1
2
3
[root@localhost shell的基本机制]# base64 <<< helloWorld
aGVsbG9Xb3JsZAo=
[root@localhost shell的基本机制]#

在批处理文件中输入重定向的定界符之后还可接着写其他命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost shell的基本机制]# cat InputRedirection.sh 
cat << TOAST
**************************
Now : `date`
My Home Directory is $HOME
**************************
TOAST

pwd
[root@localhost shell的基本机制]# bash InputRedirection.sh
**************************
Now : 2021年 06月 26日 星期六 18:23:20 CST
My Home Directory is /root
**************************
/root/Linux_Test/shell的基本机制
[root@localhost shell的基本机制]#

[root@localhost shell的基本机制]# cat InputRedirection2.sh
cat << ‘TOAST’


Now : date
My Home Directory is $HOME


TOAST

pwd
[root@localhost shell的基本机制]# bash InputRedirection2.sh


Now : date
My Home Directory is $HOME


/root/Linux_Test/shell的基本机制
[root@localhost shell的基本机制]#

历史表

历史,就是我们在Linux中曾经输入过的命令,bash会把这些命令保存下来,做成一张历史表。

历史表大小

  • 先前键入的命令存于历史表,编号递增,FIFO刷新
  • 表大小由变量HISTSIZE设定,修改HISTSIZE的配置应放入~/.bashrc

查看历史表

  • 内部命令history(文件$HOME/.bash_history)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 ......
1027 ls
1028 cd ../shell的基本机制/
1029 ls
1030 source lsdir.sh
1031 source lsdir.sh /root/Linux_Test/文件和目录的权限/
1032 ls
1033 cd ../shell的基本机制/
1034 ls
1035 ./lsdir.sh /root/Linux_Test/文件和目录的权限/
1036 ls
1037 source lsdir.sh /root/Linux_Test/文件和目录的权限/
1038 ls
1039 history
[root@localhost 文件和目录的权限]#

历史替换

  • 人机交互时直接使用上下箭头键
  • 其他引用历史机制的方法
    • !!:引用上一命令
    • !str:引用以str开头的最近用过的命令,如:!v!m!.

示例

引用上一条命令:

1
2
3
4
5
6
[root@localhost 文件和目录的权限]# ls
NewShellNewDir newShellnewFile.c sonDir test.c 验证
[root@localhost 文件和目录的权限]# !!
ls
NewShellNewDir newShellnewFile.c sonDir test.c 验证
[root@localhost 文件和目录的权限]#

引用最近使用过的以某字符串开头的命令:

1
2
3
4
5
6
7
[root@localhost 文件和目录的权限]# !l
ls
NewShellNewDir newShellnewFile.c sonDir test.c 验证
[root@localhost 文件和目录的权限]# !s
source lsdir.sh /root/Linux_Test/文件和目录的权限/
-bash: lsdir.sh: 没有那个文件或目录
[root@localhost 文件和目录的权限]#

别名和别名替换

可以给一些常用的命令取个别名,这样输入别名,就相当于运行这些命令。
如果需要,应把alias命令放入./bashrc

在别名表中增加一个别名(内部命令alias)

1
2
3
4
5
6
7
8
alias dir="ls -flad"
alias n="netstat -p tcp -s | head -10"
alias r="netstat -rn"
alias h="history"
alais t='tail -f /usr/adm/pppd.log'
alias rm='rm -i'
alias p='ping 202.143.12.189'
alias rt='traceroute 217.226.227.27‘

示例

/etc/bashrc文件末尾,加上如下命令,即可使用manen来查看英文版的命令手册:

/etc/bashrc
1
2
......
alias manen='man -L en'

https://lanlan2017.github.io/blog/6e64ba3d/#%E4%BD%BF%E7%94%A8man-L-en%E7%9A%84%E5%88%AB%E5%90%8D

查看别名表alias

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost etc]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias manen='man -L en'
alias mv='mv -i'
alias rm='rm -i'
alias su='sudo su'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
[root@localhost etc]#

取消别名(内部命令unalias)

1
unalias n #在别名表中取消n
[root@localhost etc]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias manen='man -L en'
alias mv='mv -i'
alias rm='rm -i'
alias su='sudo su'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
[root@localhost etc]# 

取消别名manen:

1
2
[root@localhost etc]# unalias manen
[root@localhost etc]#

查询别名表:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost etc]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias rm='rm -i'
alias su='sudo su'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
[root@localhost etc]#

可以看到已经没有了manen这个命令了,如果还继续输入该命令,则提示错误:

1
2
3
[root@localhost etc]# manen ls
-bash: manen: 未找到命令
[root@localhost etc]#

因为取消别名命令写在交互式的bash中,只对当前的bash影响,打开其他的bash,manen命令依然有效。

TAB键补全

在每行的首个单词中按下tab键:TAB键补全搜索$PATH下的命令
在行中的其它单词后按下tab键:TAB键补全当前目录下的文件名

启动交互式bash

三种启动方法

  • 注册shell:注册shell(用户登录系统系统时运行)
  • 键入bash命令:交互式shell(用户打开终端时运行)
  • 脚本解释器(解释.sh文件)

自动执行的一批命令(用户偏好)

  • 当bash作为注册shell启动时:自动执行用户主目录下的.bash_profile文件中命令,~/.bash_profile$HOME/.bash_profile
  • 当bash作为注册shell退出时: 自动执行$HOME/.bash_logout
  • 当bash作为交互式shell启动时: 自动执行$HOME/.bashrc
  • 类似umask之类的命令,应当写在.profile文件中

启动交互式bash

自动执行的一批命令(系统级)

  • 当bash作为注册shell启动时:自动执行/etc/profile文件中命令
  • 当bash作为交互式shell启动时: 自动执行/etc/bash.bashrc
  • 当bash作为注册shell退出时:自动执行/etc/bash.bash.logout

脚本文件

◼编辑文件lsdir(格式为文本文件,文件名不必须为.sh后缀,只是个惯例)

lsdir.sh
1
2
3
4
5
6
7
8
9
10
if [ $# = 0 ] #判断命令行的参数个数是不是0个
then
dir=. #如果是0个的话,则使用当前目录
else
dir=$1 #如果不是的话,则使用第一个参数作为目录
fi
find $dir -type d -print #查找目录下的所有子孙目录并打印
echo '----------------'
cd $dir # 修改当前工作目录到指定的目录
pwd # 打印当前工作目录

脚本文件的执行

新创建子进程,并在子进程中执行脚本

  • bash<lsdir
    • 无法携带命令行参数
  • bash lsdirbash -x lsdir(-x选项表示执行命令时,打印出正在执行的命令。这种方式可以看出命令的执行轨迹,便于debug调试),bash lsdir 目录
  • 给文件设置可执行属性x:chmod u+x lsdir然后执行./lsdir 目录

三种方法均启动程序/bin/bash,生成新进程

示例

1
2
3
4
5
[root@localhost shell的基本机制]# bash < lsdir.sh 
.
&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;&#45;
/root/Linux_Test/shell的基本机制
[root@localhost shell的基本机制]#
1
2
3
4
5
6
7
8
9
10
11
[root@localhost shell的基本机制]# bash -x lsdir.sh 
+ '[' 0 = 0 ']'
+ dir=.
+ find . -type d -print
.
+ echo ----------------
----------------
+ cd .
+ pwd
/root/Linux_Test/shell的基本机制
[root@localhost shell的基本机制]#
1
2
3
4
5
6
7
8
[root@localhost shell的基本机制]# bash lsdir.sh /root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/sonDir
/root/Linux_Test/文件和目录的权限/NewShellNewDir
/root/Linux_Test/文件和目录的权限/验证
----------------
/root/Linux_Test/文件和目录的权限
[root@localhost shell的基本机制]#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost shell的基本机制]# ls -l
总用量 4
-rw-r--r--. 1 root root 378 6月 26 15:00 lsdir.sh
[root@localhost shell的基本机制]# chmod u+x lsdir.sh
[root@localhost shell的基本机制]# ls -l
总用量 4
-rwxr--r--. 1 root root 378 6月 26 15:00 lsdir.sh
[root@localhost shell的基本机制]# ./lsdir.sh /root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/sonDir
/root/Linux_Test/文件和目录的权限/NewShellNewDir
/root/Linux_Test/文件和目录的权限/验证
----------------
/root/Linux_Test/文件和目录的权限
[root@localhost shell的基本机制]#

在当前shell进程中执行脚本

1
. lsdir.sh 参数

这里最左边的点号.会被当成内部命令运行,表示点号后面的命令在当前shell内运行。

1
source lsdir 参数

示例

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost shell的基本机制]# . lsdir.sh 
.
----------------
/root/Linux_Test/shell的基本机制
[root@localhost shell的基本机制]# . lsdir.sh /root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/sonDir
/root/Linux_Test/文件和目录的权限/NewShellNewDir
/root/Linux_Test/文件和目录的权限/验证
----------------
/root/Linux_Test/文件和目录的权限
[root@localhost 文件和目录的权限]#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost shell的基本机制]# ls
lsdir.sh
[root@localhost shell的基本机制]# source lsdir.sh
.
----------------
/root/Linux_Test/shell的基本机制
[root@localhost shell的基本机制]# source lsdir.sh /root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/sonDir
/root/Linux_Test/文件和目录的权限/NewShellNewDir
/root/Linux_Test/文件和目录的权限/验证
----------------
/root/Linux_Test/文件和目录的权限
[root@localhost 文件和目录的权限]#

启动新的shell运行与在当前shell运行的区别

脚本里有些命令会影响当前shell进程的状态,如果是启动新的shell子进程运行,则改变的是子进程的状态,对当前shell进程没有影响。

启动新的bash运行:

[root@localhost shell的基本机制]# ./lsdir.sh /root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/sonDir
/root/Linux_Test/文件和目录的权限/NewShellNewDir
/root/Linux_Test/文件和目录的权限/验证
----------------
/root/Linux_Test/文件和目录的权限
[root@localhost shell的基本机制]# ls
lsdir.sh
[root@localhost shell的基本机制]# 

在当前bash中运行:

[root@localhost shell的基本机制]# source lsdir.sh /root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/
/root/Linux_Test/文件和目录的权限/sonDir
/root/Linux_Test/文件和目录的权限/NewShellNewDir
/root/Linux_Test/文件和目录的权限/验证
----------------
/root/Linux_Test/文件和目录的权限
[root@localhost 文件和目录的权限]# ls
NewShellNewDir  newShellnewFile.c  sonDir  test.c  验证
[root@localhost 文件和目录的权限]# 

可以看到,在当前bash下运行的脚本里面的cd命令 会改变当前bash的工作路径
而启用新的bash运行的脚本,则不会改变当前bash的工作路径。

Linux shell概述

Unix的shell

shell种类

  • B-shell:由Stephen R. Bourne(1944-)在贝尔实验室开发,是最早被普遍认可的shell,早期UNIX的标准shell, /bin/sh,
  • C-shell: /bin/csh 由加利福尼亚大学的William N. Joy(也叫Bill Joy)在20世纪70年代开发,最初用在BSD2.0。Joy在1982年与他人共同创办了Sun Microsystems
  • K-shell: Korn shell,/bin/ksh 贝尔实验室的David Korn在1986年开发。是B-shell的超集,支持带类型的变量,数组
  • /bin/bash:Bourne Again shell,是Linux上的标准shell, 兼容Bourne Shell,扩展了B-shell,吸收了C shell的某特点。交互式使用时命令行编辑非常方便
  • 管理员在创建用户时,设置了用户的登录shell

Shell的功能

  • shell是命令解释器
  • 文件名替换,命令替换,变量替换
  • 历史替换,别名替换
  • 流程控制的内部命令 (内部命令和外部命令)

Shell的特点

  • 主要用途:批处理,执行效率比算法语言低
  • shell编程风格和C语言等算法语言的区别
  • shell是面向命令处理的语言,提供的流程控制结构通过对一些内部命令的解释实现
  • 如同C语言设计思路一样,shell本身设计得非常精炼,但是它提供了灵活的机制(策略与机制相分离)
    • shell许多灵活的功能,通过shell替换实现
    • 例如:流程控制所需的条件判断,四则运算,都由shell之外的命令完成

理解Unix的shell

学习bash的目的

  • 交互方式下:熟习shell的替换机制、转义机制,掌握循环等流程控制,可以编写复合命令
  • 非交互方式:编写shell脚本程序,把一系列的操作,编纂成一个脚本文件,批量处理

主要内容

  • 重定向与管道
  • 方便交互使用的功能:历史替换与别名替换
  • shell变量
  • shell的变量替换,命令替换,文件名替换
  • 元字符,如:单引号,双引号
  • 流程控制
  • 子程序

三级权限存在的问题

问题

系统中任一个用户,要么对文件的全部内容具有访问权,要么不可访问文件。有的情况下,很不方便。
◆用户修改口令,文件/etc/passwd和/etc/shadow
◆用户liu的文件list.txt:希望用户liang,只能读取行首为#的行和与他有关的行

省略……

进程实际UID/有效UID

◆一般情况下,进程的实际UID和有效UID相等。
◆打开文件open()时,系统根据进程的有效UID,与文件所有者UID之间的关系和文件的权限进行访问合法性验证
◆可执行程序具有SUID权限,进程的实际UID和有效UID不再相等。实际UID是当前用户,而有效UID为可执行文件的文件主
SUID使得用户可以通过文件主提供的程序,以文件主的权限访问文件,但这种访问依赖于文件主提供的程序,进行有限的访问