linux_shell笔记(五)

bash 作为命令解释器,同时也是高级编程语言。 作为命令解释器,他们通过提示符响应并处理用户在命令行界面上输入的命令。而作为一门编程语言,他们将处理存放在所谓shell 脚本文件中的命令。如其他编程语言一样,shell 也有变量和控制流命令。

 

当启动shell 时,它将运行初始化文件初始化自己。具体运行那个文件取决于该shell 是一个登录shell 还是一个非登录shell 的交互式shell (比如通过命令bash ),又或者是一个非交互式shell (用来执行shell 脚本)。要想运行初始化文件中的命令,用户必须具备读权限。

 

登录 shell 登录shell 以及带上—login 选项的shell ,登录shell 本身就属于交互式shell

/etc/profile shell 首先执行该文件中的命令。通过设置这个文件,超级用户可以为全系统内所有的bash 用户建立默认特性。

~/.bash_profile ~/.bash_login ~/.profile 然后shell 依次查找这些文件并执行首个文件中的命令。可以将命令放置在这些文件中以覆盖掉/etc/profile 文件中的默认值。

~/.bash_logout 当用户注销时,bash 执行文件中的命令。这个文件中包含了退出会话时需要执行的清理任务常用到的命令,比如删除临时文件等。

 

交互式非登录 shell 交互式非登录 shell 并不执行前面提到的初始化文件中的命令。然而,交互式非登录 shell 从登录 shell 继承了由这些初始化设置的 shell 变量。

/etc/bashrc 尽管不是通过bash 直接调用,许多~/.bashrc 文件还是调用/etc/bashrc 。这种安排使得超级用户可以为全系统内的非登录shell 建立默认特性。

.bashrc 交互式非登录shell 执行~/.bashrc 文件中的命令,而登录shell 的初始化文件( 比如.bash_profile) 通常会运行这个文件。这样,登录shell 和非登录shell 都可以使用.bashrc 中的命令。

 

非交互式 shell 不执行前面描述的初始化文件中的命令。然而。这些 shell 从登录 shell 那里继承了由这些初始化文件设置的 shell 变量。

BASH_ENV 非交互式 shell 查找环境变量 BASH_ENV 。并执行由该变量命名的文件中的命令。

 

句点 '.' 或者 source :在当前 shell 中运行初始化文件

在编辑诸如.bashrc 这类初始化文件之后,要使这些修改起作用,用户没有必要注销然后再次登录,可以使用内置命令'.' 或者source ,与其他命令一样,在命令行上,'.' 后面必须有一个空格。内置命令 '.' source 用起来类似于运行一个 shell 脚本,但这些命令将该脚本作为当前进程的一部分运行。因此使用 '.' source 运行脚本的时候,在脚本中改变的变量也将影响到运行该脚本的 shell

>bash example.sh

>. example.sh

>source example.sh

>ls -l example*

>chmod u+x example.sh

>./example.sh

 

>cat >example1.sh

#!/bin/bash

hahaha='example'

echo $hahaha

CONTROL+D

>chmod u+x example1.sh

>./example1.sh

>echo $hahaha

>bash example1.sh

>echo $hahaha

>. example1.sh

>echo $hahaha

注意 './example1.sh' 'bash example1.sh' 运行结果相同输出 example ,并且都对当前 shell 没有影响,也就是 'echo $hahaha' 输出为空。而最后的 '. example1.sh' 虽然同样输出 example ,但是对当前 shell 有影响 ,'echo $hahaha' 输出不为空为 'example'

 

符号命令:bash 以多种方式使用符号( ) [ ] $

重定向标准错误输出:除了标准输出之外,命令还可以将输出发送到标准错误输出。命令将错误发送到标准错误输出。默认情况shell 将标准错误发送到屏幕上。

文件描述符:当执行一个程序时,运行该程序的进程打开(从父进程继承) 3 个文件描述符,分别是 0 -标准输入, 1 -标准输出, 2 -标准错误输出。重定向符 '>' '1>' 的缩写 ,通知shell 重定向标准输出。类似的'<' '0<' 的简写'2>' 将重定向标准错误输出。

>ls

>mv example.c example.c.mv

>cat example.c example.sh

>cat example.c example.sh >hold

>cat example.c example.sh 1>hold1 2>hold2

>cat example.c example.sh | tr “[a-z]” ”[A-Z]”

>cat example.c example.sh 1>hold 2>&1

>cat example.c example.sh 2>&1 | tr “[a-z]” ”[A-Z]”

注意上面两条黑体命令行运行结果的不同:第一条由于 tr 只对其标准输入 ( 由于管道的存在也就是 cat 的标准输出 ) 进行字符替换,而并不对 cat 的标准错误输出进行替换。第二条由于 '2>&1' cat 的标准错误输出重定向到其标准输出上,所以最终 tr 的标准输入将包括 cat 的标准错误输出和标准输出。也就是说 tr 将的 cat 的标准输出和标准错误输出进行字符替换。

 

 

还可以使用'1>&2' 将命令的标准输出重定向到标准错误输出,shell 经常使用这种技术将echo 的输出发送到标准错误输出。因为我们经常重定向程序的标准输出,而并不重定向程序的标准错误输出 , 所以可是使用这项技术显示脚本的错误信息。

>cat >message_demo

echo This is an error message. 1>&2

echo This is not an error message.

CONTROL+D

>bash messag_demo > message_demo.out

>cat message_demo.out

>. message_demo >> message_demo.out

>cat message_demo.out

在脚本中,还可以使用exec 创建另外的文件描述符,并重定向shell 脚本的标准输入,标准输出和标准错误输出。

<filename 将标准输入重定向为文件filename

>filename 将标准输出重定向到文件filename

>>filename 将标准输出重定向到文件filename ,并将内容追加到文件末尾

<&m 复制文件描述符m 作为标准输入的文件描述符

>&m 复制文件描述符m 作为标准输出的文件描述符

 

shell 脚本是包含 shell 可执行命令的文件。 命令可以是用户在shell 提示符后面输入的任何命令。与在命令行输入命令一样,shell 脚本中的命令可以引用任意文件,并可以有自己的输入和输出,这些输入输出可以被重定向,脚本本身的输入和输出也可以被重定向。

除了使用用户在命令行下面输入的命令之外,shell 脚本也可以使用控制流命令。使用这些命令可以改变脚本中命令的执行顺序。

shell 一条接一条地解释并执行shell 脚本中的命令。这样使用shell 脚本就可以简单快速的启动一个复杂的任务序列或者一个重复性的过程。

要想用 shell 脚本的文件名作为命令执行该脚本,用户必须具有该脚本的文件读权限和执行权限。 如果将文件名作为bash 的参数,那么bash 将参数作为一个shell 脚本并执行他,这时,bash 是可执行的,而该文件是要执行的参数,因此用户不必具备该文件的执行权限,但是依然需要具有读权限。

>example.sh

>./example.sh

>bash example.sh

>ls -l example.*

>chmod u+x example.sh

>./example.sh

默认情况下shell 并不在当前工作目录下查找可执行文件,所以需要使用'./' 明确告诉是在当前目录下查找可执行文件

任何用户想要把文件名作为命令执行,都必须具备执行访问权。如果该文件是一个 shell 脚本,用户必须具备读访问权限。而在执行一个二进制文件时,并不需要读访问权限。

 

#! 指定shell

shell 脚本文件的第一行可以放置一行特殊的字符串,告诉操作系统使用哪个shell 来执行这个文件。如果脚本的前两个字符是 #! ,那么系统将这两个字符后面的那些字符作为用来执行该脚本的命令解释器的绝对路径名。 他可以是任何程序的路径名,而并不仅仅是 shell

>cat >bash_script

echo “This is a bash script.”

CONTROL+D

>chmod u+x bash_script

>./bash_script

>cat >>bash_script

ps -f

CONTROL+D

>./bash_script

# 开始一行注释 如果'#' 号在脚本第一行出现并且其后没有感叹号'!' ,或者脚本中其他任意位置上出现了# ,那么shell 将其视为注释的开始。

 

执行shell 脚本:

fork exec 系统调用 用户在命令行上输入一条命令之后, shell fork 一个新的进程,以创建当前 shell 进程的一个副本(继承父进程地址空间等)。这个新的进程将试图 exec (执行)该命令。如果该命令是一个二进制可执行文件,那么 exec 成功,系统使用该可执行程序覆盖新创建的 shell (通过读该可执行文件中的代码段 数据段等形式实现自己的地址空间)。而如果这个命令是一个 shell 脚本, exec 失败,失败后子 shell 通过判断文件是否以 '#!' 开始来确定该文件是否为 shell 脚本,如果是将执行该脚本中的命令。子 shell 从该脚本中获取输入。

如果不具备shell 脚本文件的执行权限,那么用户可以使用bash 命令来exec 一个shell 直接运行该脚本,这样就可以运行脚本中的命令。

 

命令分割和命令分组:

当用户交互式地向shell 输入命令时,或者在编写shell 脚本时,必须分隔不同的命令。

使用; 和换行符分割命令 用户可以在单独一个命令行中连续输入一串命令,并用; 隔开。它并不立即启动命令执行,也不改变命令的任何功能。

>x;y;z

>x

>y

>z

>cat example.c;vim example.c

>cat example.c;vim example.c &

>ls;ps;xclock;xclock&

最后一条命令只是使得最后一个 xclock 运行在后台。

/ 继续命令 当输入一个比较长的命令行时,光标已经到达屏幕的右端,这时候可以使用反斜杆在下一行继续命令的输入。反斜杆转义换行符,这样shell 就不会将这个换行符作为一个命令终结符对待。

>echo Please enter the three values /RETURN

required to complete the transaction. RETURN

>echo “Please enter the three values /RETURN

required to complete the transaction .”RETURN

>echo “Please enter the three values RETURN

required to complete the transaction.”RETURN

>echo 'Please enter the three values /RETURN

required to complete the transaction.'RETURN

注意在输入有 ' 或者”的命令行时按照顺序输入,不可先将成对的引号输入完毕后再在其中输入文字,在该情形下,输入引号中间的 RETURN 时将开始命令的执行,而不能将其转义。

 

| & 分隔命令 及其他功能 管道符号和任务符号也是命令分隔符。他们并不开始执行命令而是在某些方面改变命令的功能。管道符号改变标准输入的源或者是标准输出的目的地。而后台任务符使shell 在后台执行该任务。

>ls -l | grep tmp | less

>x | y | z

>d & e & f

>d & e & f &

>d | e | f &

>ls -l | grep tmp | less &

最后一个命令行利用& 将整个作业作为一个后台任务运行。

 

作业控制 一个作业是一个命令流水线。使用作业控制可以将命令从前台移到后台,或者从后台移到前台 。还可以临时停止命令,以及列出所有正在后台执行的命令或者是已经停止的命令。

Jobs 列出作业 内置命令jobs 将列出所有后台作业

>sleep 60 &

>jobs

将作业移到前台运行

shell 为那些运行在后台的命令指派了作业编号。

>xclock &

>xclock &

>jobs

>fg %1

CONTROL + Z

>jobs

>bg %1

>jobs

>kill %1

>fg %2

CONTROL+C

>jobs

在将一个前台作业转移到后台执行之前,必须使用挂起键 CONTROL Z 将其挂起。然后利用 bg 命令将该任务放置到后台运行。

>vim example.c &

>jobs

>fg %1

SHIFT+ZZ

>jobs

>cat >mytxt &

>jobs

>fg %1

This is my text

CONTROL+D

>jobs

 

bash 允许用户将正在使用的目录列表存放起来,这样就可以在这些目录之间轻易移动,这个目录列表称为目录栈。

Dirs 显示栈,pushd 将目录压入栈中,该命令可以改变目录同时将添加一个新的目录到栈中。

>dirs

 

不管是否显式地创建目录栈,都可以使用 cd - 切换到前一个目录。

>pwd

>cd ~

>cd exampledoc

>pwd

>cd -

>pwd

>cd -

 

参数和变量,在shell 中,shell 参数与用户可访问的某个值相关。有几种不同的shell 参数。参数的名字由字母 数字和下划线组成,常称为shell 变量,或者简称变量。变量名必须以字母或者下划线开头,而不是数字。

用户命名并赋值的 shell 变量称为用户创建的变量。可以将用户创建的变量变成全局变量。全局变量只使用大写字母,而其他变量则使用大小写混合。

VARIABLEvalue

>myvar=abc

>echo myvar

>echo $myvar

>echo “$myvar”

>echo '$myvar'

>echo /$myvar

 

>cat >my_script

echo $TEMPDIR

CONTROL+D

>chmod u+x my_script

>TEMPDIR=/home/terry ./my_script

>echo $TEMPDIR

>TEMPDIR=/home PATH=$PATH:. my_script

>echo $PATH

bash 允许在命令行中放置变量赋值语句。这些赋值语句只是在该命令 shell 的局部行为,也就是说它们只适合于该命令。黑体命令行定义的变量只对执行 my_script shell 有影响。

 

>person =alex and jenny

>person=”alex and jenny and RETURN

terry”

>echo $person

>echo “$person”

>memo=example*

>echo $memo

>echo “$memo”

>echo '$memo'

 

语法 $VARIABLE ${VARIABLE} 的特殊情形,后者更加通用。

>PREF=counter

>WAY=$PREFclockwise

>FAKE=$PREFfeit

>echo $WAY $FAKE

>WAY=${PREF}clockwise

>FAKE=${PREF}feit

>echo $WAY $FAKE

除非变量被删除,否则它将伴随它的 shell 一直存在。 Unset 删除变量。

>unset person

>unset WAY

>unset PREF FAKE

 

变量属性 readonly 使变量值不可变更 readonly 确保某个变量的值不被改变。如果尝试删除或者改变只读变量的值,shell 将提示错误消息。

>declare | grep person

>unset person

>declare | grep person

>person=jenny

>echo $person

>person=terry

>echo $person

>readonly person

>person=terry2

>declare | cat -n | grep person

>readonly | less

不带参数使用readonly 时,它会显式所有只读变量列表。(和declare -r 产生相同的输出)

 

对变量赋予属性:declaretypeset

内置命令 declare typeset 用来设置 shell 变量的属性和值。

-a 声明一个数组变量

-f 声明一个函数名变量

-i 声明一个整形变量

-r 声明变量为只读,也可用readonly

-x 输出变量,设置为全局,也可用export

 

>declare person1=alex

>declare -r person2=jenny

>declare -rx person3=helen

>declare -x person4

>declare | cat -n | grep person

内置命令readonlyexport 分别与命令declare -r declare -x 同义。

将命令行中的连字符换成字符+ ,可以为变量删除某个属性 ,但是,用户不能删除只读属性。

>declare +x person3

set bash 中不能用来定义变量

 

 

 

不带任何参数或者选项,那么内置命令 declare 将列出所有 shell 变量。不带任何参数运行 set 命令,也会得到同样的结果。 如果内置命令declare 带有选项,但是没有参数,那么,该命令将列出所有具有指定属性集合的shell 变量。

>declare | cat -n | less

>declare -r | cat -n | less

 

关键字变量 既可以通过继承而来,也可以在shell 启动时声明并初始化。可以通过命令行方式或者在初始化文件中为这些变量指派值。那些不是 shell 自动输出的变量,用户必须使用 export 使这些变量也可以被子 shell 访问。

HOME 用户主目录。默认情况下,用户主目录就是用户登录后的工作目录。当用户被创建时,其主目录就确认下来了。这个文件名保存在文件/etc/passwd 中。

>cat -n /etc/passwd

用户登录后,shell 继承了用户的主目录的路径并将其赋值给HOME

>cd /etc

>pwd

>cd

>pwd

>echo $HOME

代字符~ shell 使用 HOME 的值来展开路径名,该路径名使用简写形式(代字符 ~ )来表示用户的主目录。

>echo ~

>cd ~

>ls ~/exampledoc

 

PATH shell 查找程序的路径, 在向 shell 中输入一个绝对路径名或者相对路径名,而不是一个简单的文件名作为命令时, shell 就会在指定的这个目录下,用指定的文件名查找执行文件。如果使用简单文件名作为命令, shell 将搜索某些目录,以查找用户想要执行的程序。变量 PATH 控制着这些搜索路径。

>pwd

>cd ~/exampledoc

>ls -l

>./morning

>echo $PATH

>morning

>PATH=$PATH:. morning

 

MAIL 保存电子邮件的地方 包含了保存用户邮件文件的路径名。

MAILPATH 包含一个冒号隔开的文件列表。如果设置了这个变量,那么当这个列表中的任何一个文件发生改变时,shell 将提醒用户。可以在该列表中任何一个文件名后面加上一个问号(?) ,问号后面跟一条消息。如果有新邮件,shell 将显示该消息。

MAILCHECK 规定了shell 以多大的频度检查新邮件。默认是60 秒。

 

PS1 用户主提示符 保存了 shell 用来提示用户输入命令的提示字符串。 当用户修改PS1 时用户提示符号、将会发生改变。

>echo $PS1

/$ 如果以 root 登录,就显示 # ,否则是 $

/w 工作目录的路径名

/W 工作目录的基名

/! 当前事件编号

/d 显示日期

/h 主机名

/H 主机名 包括域名

/u 用户名

/@ 当前时间

/T 当前时间

/A 当前时间

/t 当前时间

 

PS2 用户次提示符

>echo $PS2

PS3 菜单提示符

PS4 调试提示符

 

IFS 分隔输入字段 指定了在命令行中用来分隔参数的字符,其默认值为空格符 制表符 和 换行符

>echo $IFS

>a=w:x:y:z

>cat $a

>IFS=”:”

>cat $a

>cat w:x:y:z

shell 根据 IFS 中发现的分隔符划分命令行中所有被展开的字。如果不进行展开,就不会进行分词,如上面最后一个命令行将不会分词而倒数第二个命令行会分词 - 因为要展开。

 

CDPATH 扩大 cd 的范围 ,用户可以用一个简单的文件名作为参数传递给内置命令cd ,就将工作目录改变到某个目录,而这个目录并不是工作目录的子目录。如果工作中需要多个目录,那么这个变量可使得工作更有效率。

如果没有设置CDPATH ,而只是指定一个简单的文件名作为调用cd 的参数,那么cd 将在工作目录中查找具有与该参数相同的文件名的子目录。而如果设置了 CDPATH cd 将在 CDPATH 列表中的目录搜索具有与该参数相同的文件名的子目录。 设置CDPATH ,用户可以使用cd 和一个简单的文件名可以将工作目录切换到CDPATH 中的任何一个目录的子目录。

>pwd

>cd ~

>cd etc

>cd exampledoc

>echo $CDPATH

>CDPATH=$HOME:/

>pwd

>cd etc

>cd proc

>cd exampledoc

>unset CDPATH

如果传递给内置命令 cd 的参数是一个绝对的文件名,一个以斜线 (/) 开头的文件名,则 shell 就不会考虑 CDPATH

 

 

你可能感兴趣的:(linux_shell笔记(五))