[ 上一篇 ] [ 目录 ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ 14 ] [ 15 ] [ 16 ] [ 17 ] [ 18 ] [ A ] [ B ] [ C ] [ D ] [ 下一篇 ]
每个进程都关联着一个环境。环境是环境变量的集合。变量是一个具有固定名称的可变值。例如,名称 EMAIL 可以指代值 joe@nowhere.com。值可以变化 --- EMAIL 也可以指代 jane@somewhere.com。
由于您的 shell 和其他进程一样也是一个进程,因此它也有一个环境。您可以通过输入 printenv 命令来查看您的 shell 环境。以下是一些示例输出
PAGER=less HOSTNAME=icon MAILCHECK=60 MOZILLA_HOME=/usr/local/lib/netscape PS1=$ USER=hp MACHTYPE=i486-pc-linux-gnu EDITOR=jed DISPLAY=:0.0 LOGNAME=hp EMAIL=hp@pobox.com SHELL=/bin/bash HOSTTYPE=i486 OSTYPE=linux-gnu HISTSIZE=150 HOME=/home/hp TERM=xterm-debian TEXEDIT=jed PATH=/home/hp/local/bin:/usr/sbin:/home/hp/.bin:/home/hp/local/bin:/usr/sbin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:. _=/usr/bin/printenv
在您的系统上,输出将有所不同,但会类似。
环境变量是配置系统的一种方式。例如,EDITOR 变量允许您选择您首选的编辑器来发布新闻、撰写电子邮件等等。HISTSIZE 变量告诉 Bash 要在其历史记录中保留多少命令行;您可以使用向上箭头键返回到那么多命令行。
设置环境变量很简单。一旦您学会了如何操作,您可能想要在每次登录时自动设置它们;请参阅自定义 shell,第 9 章以获取说明。
为了练习,尝试使用环境变量自定义您的 shell 提示符和文本文件查看器
man less
查看 less 命令的在线手册。为了每次向您显示一屏幕文本,man 调用了一个分页器,每次您按下空格键时,它都会向您显示新的一页文本。默认情况下,它使用名为 more 的分页器。
继续浏览 less 的手册页,它是一个增强的分页器。按空格键滚动到新的一页;按 q 退出。more 也会在您到达手册页末尾时自动退出。
export PAGER=less
在阅读了 less 的优点后,您可能想使用它来阅读手册页。为此,您需要设置环境变量 PAGER。
在 bash 中设置环境变量的命令始终具有以下格式:export NAME=value。如果您碰巧运行 tcsh 或另一个 C Shell 衍生版本,则等效命令是 setenv NAME value。
export 意味着将变量从 shell 移动到环境中。这意味着 shell 以外的程序将能够访问它。
echo $PAGER
这是查看变量值的最简单方法。$PAGER 告诉 shell 在调用命令之前插入 PAGER 变量的值。echo 将其参数回显:在本例中,它回显当前的 PAGER 值,less。
man more
阅读 more 手册。这一次,man 应该调用了 less 分页器。
less 具有许多 more 缺乏的功能。例如,您可以使用 b 键向后滚动。您还可以使用箭头键向上和向下(甚至左右)移动。less 不会在到达手册页末尾时退出;它会等待您按下 q。
PAGER=more man more
如果您想要临时使用不同的设置,您可以仅对当前命令行生效的新值。将 NAME=value 放在命令行的开头,后跟要执行的命令。请务必省略 export。
您可以尝试一些 less 特有的命令,例如 b,以验证它们是否不适用于 more 并且您确实正在使用 more。
echo $PAGER
PAGER 的值应该仍然是 less;上面的设置只是临时的。
unset PAGER
如果您不想再指定分页器,您可以 unset 该变量。man 然后将默认使用 more,就像您设置变量之前一样。
echo $PAGER
由于 PAGER 已被取消设置,echo 将不会打印任何内容。
PS1=hello
只是为了好玩,更改您的 shell 提示符。$ 应该变成 hello:。
export 不是必需的,因为我们正在更改 shell 自身的行为。没有理由将变量导出到环境中供其他程序查看。从技术上讲,PS1 是一个shell 变量,而不是环境变量。
如果您愿意,您可以 export shell 变量,将其转换为环境变量。然后其他程序可以看到它:具体来说,是当前 shell 进程的子进程。下一节将对此进行解释。
所有进程都来自较早的进程,称为它们的父进程。[10] ps
命令是探索进程的有用工具,它可以用来检查父子关系。
ps f
此命令要求查看属于您的进程列表,格式显示进程之间的关系。
ps f 可能会产生如下输出
$ ps f PID TT STAT TIME 7270 p5 S 0:00 bash 15980 p5 R 0:00 \_ ps f 19682 p4 S 0:00 bash 15973 p4 S 0:00 \_ man ps 15976 p4 S 0:00 \_ sh -c /bin/gzip -dc '/var/catman/cat1/ps.1.gz' | { export MAN_PN LESS; MAN_PN='ps(1)'; LESS="$LESS\$-Pm\:\$i 15977 p4 S 0:00 \_ /bin/gzip -dc /var/catman/cat1/ps.1.gz 15978 p4 S 0:00 \_ sh -c /bin/gzip -dc '/var/catman/cat1/ps.1.gz' | { export MAN_PN LESS; MAN_PN='ps(1)'; LESS="$LESS\$-Pm\ 15979 p4 S 0:00 \_ less $
在这里您可以看到我正在运行许多进程,包括两个 shell。这些 shell 有子进程:shell 进程 7270 有子进程 15980 (ps f),shell 19682 有子进程 15973 (man ps)。man ps 又调用了一组复杂的子进程,以便显示手册页。现在不用担心这些子进程做什么。
父进程和子进程之间存在复杂的关系。大多数时候,当父进程死亡时,子进程也会死亡。因此,您可以通过杀死父进程 15973 来杀死整组进程 --- 例如,上面示例中所有 man ps 子进程。
子进程继承其父进程的环境变量以及一些其他属性,例如当前工作目录。
当 shell 运行命令时,它会将命令作为子进程生成。因此,man 命令继承了 shell 的环境;如果您设置了 PAGER 变量,man 将能够看到它。
如果您未能 export 变量,则只有 shell 自身会看到它,并且它不会传递给子进程,例如 man。
当您在 shell 中键入命令时,它必须在硬盘上找到程序才能执行它。如果 shell 必须在整个磁盘上查找,那将会非常慢;相反,它会在 PATH 环境变量中包含的目录列表中查找。此目录列表构成了 shell 的搜索路径;当您输入命令时,它会依次遍历每个目录,查找您要求运行的程序。
如果您自己在非标准位置安装程序,您可能需要更改 PATH 变量。
PATH 的值是以冒号分隔的目录列表。Debian 系统上的默认值为
/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games
此值在文件 /etc/profile 中定义,并适用于所有用户。您可以轻松更改该值,就像您可以更改任何环境变量一样。
如果您键入命令 ls,shell 将首先在 /usr/local/bin 中查找;ls 不在那里,因此它将尝试 /usr/bin;当失败时,它将检查 /bin。在那里它将发现 /bin/ls,停止搜索,并执行程序 /bin/ls。如果 /usr/bin/X11/ls 存在(它不存在,但假设存在),它将被忽略。
您可以使用 type 命令查看 shell 将要使用的 ls。type ls 将给您答案 /bin/ls --- 自己尝试一下。
尝试询问 type 自身位于何处
$ type type type is a shell builtin
type 实际上不是一个程序;它是 shell 提供的一个函数。但是,您像使用外部程序一样使用它。[11]
有许多类似的命令;键入 man builtins 以阅读描述它们的手册页。通常,您不需要知道命令是内置命令还是实际程序;但是,内置命令不会显示在 ps 或 top 的输出中,因为它们不是单独的进程。它们只是 shell 的一部分。
如果您经常使用相同的命令,您可能会厌倦键入它。bash 允许您为您的命令编写更短的别名。您还可以编写shell 函数,它们是由多个其他命令组成的自定义命令。
假设您总是使用 ls 的 --almost-all 和 --color=auto 选项。您很快就会厌倦键入 ls --almost-all --color=auto。因此您创建了一个别名
alias myls='ls --almost-all --color=auto'
现在您可以键入 myls 而不是完整命令。要查看 myls 实际上是什么,请运行命令 type myls。要查看您已定义的别名列表,只需在单独的一行上键入 alias。
Shell 函数比别名更灵活。别名只是在您键入较短的命令时替换为较长的命令。函数允许您使用一系列命令来执行某些操作。
首先让我们看看如何使用 shell 函数来代替上面的别名
myls() { ls --almost-all --color=auto $* }
上面称为函数定义,因为它给出了一个函数名称 (myls),然后定义了名称的含义(要执行的一些命令)。要定义一个函数,请编写其名称,后跟 ()。然后将要执行的命令包含在花括号 ({}) 内。花括号内的部分称为函数的 主体。
函数的参数可以称为 $*。因此,如果您键入
myls /usr /etc
$* 将是 /usr /etc,即两个参数。如果没有参数,$* 将为空。
您还可以按数字引用参数。因此,函数主体中的 $1 将被替换为 /usr,$2 将被替换为 /etc。输入此函数(您可以在 shell 提示符下键入它;每行后按回车键)
print_arguments() { echo "First argument: $1" echo "Second argument: $2" echo "All arguments: $*" }
您可以使用 type 命令验证您是否正确输入了函数定义;type print_arguments 应该说
print_arguments is a function print_arguments () { echo "First argument: $1"; echo "Second argument: $2"; echo "All arguments: $*" }
试用该函数。如果您输入 print_arguments one two,它将显示
First argument: one Second argument: two All arguments: one two
您可以在 shell 函数中执行更多复杂的操作;您只受您的想象力限制。有关更多信息,请参阅shell 脚本入门,第 16.1 节。
标准输入、标准输出、管道和重定向
每个进程至少有三个与外部世界的连接。标准输入是进程数据的一个来源;标准输出是进程发送数据的一个位置;标准错误是进程可以发送错误消息的位置。(这些通常缩写为 stdin、stdout 和 stderr。)
“来源”和“位置”这两个词有意含糊不清。这些标准输入和输出位置可以由用户更改;它们可以是屏幕、键盘、文件,甚至是网络连接。用户可以指定要使用的位置。
当您从 shell 运行程序时,通常标准输入来自您的键盘,标准输出和错误都转到您的屏幕。但是,您可以要求 shell 更改这些默认值。
例如,echo 命令将其输出发送到标准输出,通常是屏幕。但是您可以使用输出重定向运算符 '>' 将其发送到文件。例如,要将单词“Hello”放入文件 myfile 中
echo Hello > myfile
使用 cat 或您的文本文件分页器 (more 或 less) 查看 myfile 的内容。
您可以使用输入重定向运算符 '<' 更改命令的标准输入。例如,more < myfile 将显示 myfile 的内容。这在实践中没有用处;为了方便起见,more 命令接受文件名参数。因此,您可以简单地说 more myfile,效果将是相同的。
在底层,more < myfile 意味着 shell 打开 myfile,然后将其内容馈送到 more 的标准输入。more myfile,没有重定向运算符,意味着 more 命令接收一个参数 myfile,自行打开文件,然后显示该文件。
但是,存在双重功能是有原因的。例如,您可以将一个命令的标准输出连接到另一个命令的标准输入。这称为管道,它使用管道运算符 '|'。
也许您想反向查看 GNU 通用公共许可证。为此,您可以使用 tac 命令(它是 cat,只是反向的)。尝试一下
tac /usr/doc/copyright/GPL
不幸的是,它过得太快而无法阅读。因此您只能看到几个段落。解决方案是管道
tac /usr/doc/copyright/GPL | more
这获取 tac 的标准输出,即反向的 GPL,并将其发送到 more 的标准输入。
您可以将任意数量的命令链接在一起。假设您莫名其妙地想要将每个 G 替换为 Q;为此,您可以使用命令 tr G Q,如下所示
tac /usr/doc/copyright/GPL | tr G Q | more
您可以使用临时文件和重定向获得相同的效果。例如
tac /usr/doc/copyright/GPL > tmpfile tr G Q < tmpfile > tmpfile2 more < tmpfile2 rm tmpfile tmpfile2
显然,管道更方便。
“修饰符”,如 batch、at、nohup、nice
通常,您希望命令处理一组文件。“通配符”用于创建文件名展开模式:一系列字符和通配符,展开为文件名列表。例如,模式 /etc/* 展开为 /etc 中所有文件的列表 [12]。* 是一个通配符,可以代表任意一系列字符,因此模式 /etc/* 将展开为以 /etc/ 开头的所有文件名的列表。
此文件名列表最有用作命令的一组参数。例如,/etc 目录包含一系列名为 rc0.d、rc1.d 等的子目录。通常要查看这些目录的内容,您需要键入
ls /etc/rc0.d /etc/rc1.d /etc/rc2.d /etc/rc3.d /etc/rc4.d /etc/rc5.d /etc/rc6.d /etc/rcS.d
这很乏味。相反,您可以使用 ? 通配符
ls /etc/rc?.d
/etc/rc?.d 展开为以 rc 开头,后跟任意单个字符,后跟 .d 的文件名列表。
可用的通配符有
匹配任意组的 0 个或多个字符
精确匹配一个字符
如果您将一些字符括在方括号中,结果是一个通配符,它匹配这些字符。例如,[abc] 匹配 a、b 或 c。如果您在第一个方括号后添加 ^,则意义相反;因此 [^abc] 匹配任何不是 a、b 或 c 的字符。您可以包含一个范围,例如 [a-j],它匹配 a 和 j 之间的任何内容。匹配区分大小写,因此要允许任何字母,您必须使用 [a-zA-Z]。
展开模式很简单,一旦您看到一些具体的例子
这将为您提供任何以 .txt 结尾的文件名列表,因为 * 匹配任何内容。
这将为您提供以 .h 或 .c 结尾的文件名列表。
这将为您提供所有以 a 开头的三字母文件名。
这将为您提供所有不以 a 开头的三字母文件名。
这将为您提供每个以 a 开头的文件名,无论有多少个字母。
Bash 有两种不同的模式:交互式和非交互式。交互式意味着您可以键入内容,并让它为您做事。非交互式 shell 解释 shell 脚本,类似于 DOS 批处理文件。您给它一个要执行的命令列表,它会去执行它们,但无需您的干预。您看不到所有键入的命令。当然,任何输出都将记录在某处(标准输出或 stdout,通常是屏幕或日志文件)。稍后我们将更深入地探讨非交互式 shell。
交互式 shell 将需要很长时间才能掌握,仅仅是因为它们非常强大 --- 您可能永远学不完所有内容!shell 可以做的事情太多了,当然它总是在变化。我们将在这里讨论 bash,以及一些使您使用 shell 更轻松的基本命令。在 bash 中,可以同时进行几件不同的事情,这可能会让人感到困惑。
Shell 是面向行或命令行的环境。当 shell 等待您执行操作时,它总是会用提示符提示您。默认的 debian 提示符是 $。在 $ 提示符下,您可以键入命令来告诉 linux 做事,它可以是程序名称,也可以是 shell 为您方便提供的“内置”命令。
[ 上一篇 ] [ 目录 ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] [ 5 ] [ 6 ] [ 7 ] [ 8 ] [ 9 ] [ 10 ] [ 11 ] [ 12 ] [ 13 ] [ 14 ] [ 15 ] [ 16 ] [ 17 ] [ 18 ] [ A ] [ B ] [ C ] [ D ] [ 下一篇 ]
Debian 教程 (过时文档)
2009 年 12 月 29 日hp@debian.org