Linux命令行Shell

admin 2023-10-14 904 阅读 0评论

为了在Linux系统上运行命令,你需要一个地方来输入它们。这个“地方”被称为shell,这是Linux的命令行用户界面:你输入一个命令,按回车,然后shell就会运行你请求的程序。

例如,要查看谁在电脑上登录了,你可以在shell中执行这个命令:

→ who
silver       :0    Sep 23 20:44
byrnes    pts/0    Sep 15 13:51
barrett   pts/1    Sep 22 21:15
silver    pts/2    Sep 22 21:18

一个命令也可以同时调用多个程序,甚至可以将程序连接在一起,使它们互相交互。这里有一个命令,它将who程序的输出重定向为wc程序的输入,wc程序可以计算文件中的文本行数;结果就是who的输出中的行数:

→ who | wc -l
4

告诉你有多少用户正在登录。竖线,叫做管道,连接了whowc

shell实际上也是一个程序,而且Linux有好几种。我们主要关注的是bash(Bourne-Again Shell),位于*/bin/bash*,通常是Linux发行版的默认选项。要查看你是否正在运行bash,输入:

→ echo $SHELL
/bin/bash

Shell与程序的区别

当你运行一个命令时,它可能会调用一个Linux程序(像who),或者可能是一个内置命令,是shell本身的一个功能。你可以使用type命令来区分:

→ type who
who is /usr/bin/who
→ type cd
cd is a shell builtin

bash Shell的一些特性

shell不仅仅是运行命令。它还具有强大的功能来使这个任务更容易:用于匹配文件名的通配符,“命令历史”用于快速回调之前的命令,管道用于将一个命令的输出变为另一个命令的输入,变量用于存储shell使用的值,等等。花时间学习这些功能,你会在Linux上变得更快、更高效。让我们浅尝辄止的为你介绍这些有用的工具。(要查看完整的文档,运行info bash。)

通配符

通配符是一种用于表示具有相似名称的文件集合的简写。例如,a*表示所有以小写字母“a”开头的文件。通配符由shell“展开”为实际匹配的文件名集合。所以,如果你输入:

→ ls a*

shell首先将a*展开为你当前目录中以“a”开头的文件名,就像你输入的那样:

→ ls aardvark adamantium apple

ls从来不知道你使用了通配符:它只看到shell展开通配符后的最终文件名列表。这意味着每一个Linux命令,无论其来源,都可以与通配符和其他shell特性一起使用。这一点非常重要。许多Linux用户错误地认为程序会扩展自己的通配符。但事实并非如此。通配符完全由shell在关联的程序运行之前处理。

点文件

以点开始的文件名,在Linux中被称为点文件,是特殊的。当你以一个点开始命名文件时,它将不会被一些程序显示:

  • • ls会从目录列表中省略这个文件,除非你提供-a选项。

  • • shell的通配符不会匹配开始的点。

实际上,除非你明确要求查看它们,否则点文件是隐藏的。因此,有时它们被称为“隐藏文件”。

通配符永远不会匹配两个字符:一个开始的点,和目录斜杠(/)。这些必须按字面给出,比如.pro*来匹配*.profile,或者/etc/*conf来匹配/etc目录中以conf*结束的所有文件名。

通配符含义
*零个或多个连续的字符
?任意单个字符
[*set*]给定*set*中的任何单个字符,最常见的是一串字符,如[aeiouAEIOU]表示所有的元音,或者带破折号的范围,如[A-Z]表示所有的大写字母
[^*set*]不在给定*set*中的任何单个字符,如[^0-9]表示任何非数字字符
[!*set*][^*set*]相同

当使用字符集时,如果你想在集合中包含一个字面上的破折号,把它放在首位或者末位。要在集合中包含一个字面上的关闭方括号,把它放在首位。要字面上包含^!符号,不要把它放在首位。

花括号扩展

与通配符类似,带有花括号的表达式也会扩展成命令的多个参数。逗号分隔的表达式:

{X,YY,ZZZ}

首先扩展为X,然后是YY,最后是ZZZ,在命令行中,就像这样:

→ echo sand{X,YY,ZZZ}wich
sandXwich sandYYwich sandZZZwich

花括号适用于任何字符串,不像通配符,它们只有在匹配到现有文件名时才会扩展。

Shell变量

你可以通过赋值来定义变量及其值:

→ MYVAR=3

要引用一个值,只需在变量名前加一个美元符号:

→ echo $MYVAR
3

一些变量是系统的,通常在你登录时由shell定义:

变量含义
DISPLAY你的X窗口显示名
HOME你的主目录,例如 /home/smith
LOGNAME你的登录名,例如 smith
MAIL你的收件邮箱,例如 /var/spool/mail/smith
OLDPWD你的shell在最后一个cd命令之前的目录
PATH你的shell搜索路径:由冒号分隔的目录
PWD你的shell的当前目录
SHELL你的shell路径(例如,*/bin/bash*)
TERM你的终端类型(例如,xterm或vt100)
USER你的登录名

变量的作用范围(即,哪些程序知道它)默认是在定义它的shell中。要使变量及其值可用于shell调用的其他程序(即,子shell),使用export命令:

→ export MYVAR

或者简写形式:

→ export MYVAR=3

你的变量现在被称为环境变量,因为它对你的shell的“环境”中的其他程序可用。所以在前面的例子中,导出的变量MYVAR对由同一个shell运行的所有程序(包括shell脚本:参见[“Variables”])都可用。

要列出shell的环境变量,运行:

→ printenv

要为特定程序提供环境变量的值一次,将*variable=value*添加到命令行前面:

→ printenv HOME
/home/smith
→ HOME=/home/sally printenv HOME
/home/sally
→ printenv HOME
/home/smith            原始值不受影响

搜索路径

程序散布在Linux文件系统的各处,比如*/bin/usr/bin*这样的目录。当你通过shell命令运行程序时,shell是如何找到它的?关键的变量PATH告诉shell在哪里查找。当你输入任何命令:

→ who

shell通过搜索Linux目录来找到who程序。shell查阅PATH的值,这是由冒号分隔的一系列目录:

→ echo $PATH
/usr/local/bin:/bin:/usr/bin

并在这些目录中查找who命令。如果它找到了who(比如,*/usr/bin/who*),它就运行该命令。否则,它会报告一个错误,比如:

bash: who: command not found

要暂时向你的shell的搜索路径添加目录,可以修改它的PATH变量。例如,要将*/usr/sbin*添加到你的shell的搜索路径中:

→ PATH=$PATH:/usr/sbin
→ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/sbin

这个改变只影响当前的shell。要使它永久有效,可以在你的启动文件*/.bash_profile中修改PATH变量。然后注销并重新登录,或者在你的所有打开的shell窗口中手动运行你的/.bash_profile*启动文件:

→ . $HOME/.bash_profile

别名

内建命令alias可以定义一个方便的简写来替代长命令,以节省打字。比如:

→ alias ll='ls -lG'

定义了一个新命令ll,用来运行ls -lG

→ ll
总计 436
-rw-r--r--    1 smith     3584 Oct 11 14:59 file1
-rwxr-xr-x    1 smith       72 Aug  6 23:04 file2
...

在你的 ~/.bash_aliases 文件中定义别名,就可以在你每次登录时使用了。输入alias可以查看你所有的别名。

输入/输出重定向

Shell可以将标准输入、标准输出和标准错误重定向到文件(参见["输入和输出"])。换句话说,任何从标准输入读取的命令都可以使用Shell的 < 操作符将输入来自文件:

→ any command < infile

同样,任何写到标准输出的命令都可以改为写到文件:

→ any command > outfile      创建/覆盖 outfile
→ any command >> outfile     追加到 outfile

写到标准错误的命令也可以将其输出重定向到文件,而标准输出仍然显示在屏幕上:

→ any command 2> errorfile

要将标准输出和标准错误都重定向到文件:

→ any command > outfile 2> errorfile   分别到两个文件
→ any command >& outfile               同一个文件
→ any command &> outfile               同一个文件

管道

你可以用Shell的管道(|)操作符将一个命令的标准输出重定向为另一个命令的标准输入。(在美国键盘上,你可以在Enter键上方找到这个符号。)比如:

→ who | sort

who的输出发送到sort程序,打印一个按字母顺序排序的已登录用户列表。多个管道也可以工作。在这里,我们再次排序who的输出,提取第一列的信息(使用awk),并一页一页地显示结果(使用less):

→ who | sort | awk '{print $1}' | less

进程替换

管道让你可以将一个程序的输出发送给另一个程序。一个更高级的特性,进程替换,让该输出可以伪装成一个命名文件。考虑一个比较两个文件内容的程序。用进程替换操作符,<(),你可以比较两个程序的输出。

假设你有一个文件夹装满了成对的JPEG和文本文件:

→ ls jpegexample
file1.jpg  file1.  file2.jpg  file2. ...

你想确认每个JPEG文件是否都有对应的文本文件,反之亦然。通常,你可能会创建两个临时文件,一个包含JPEG文件名,另一个包含文本文件名,用cut移除文件扩展名,然后用diff比较两个临时文件:

→ cd jpegexample
→ ls *.jpg | cut -d. -f1 > /tmp/jpegs
→ ls *. | cut -d. -f1 > /tmp/texts
→ diff /tmp/jpegs /tmp/texts
5a6
> file6       没有找到file6.jpg
8d8
< file9       没有找到file9.

有了进程替换,你可以用一条命令完成同样的任务,而不需要临时文件:

→ diff <(ls *.jpg|cut -d. -f1) <(ls *.|cut -d. -f1)

每个<()操作符都代表了命令行上的一个文件名,就像那个“文件”包含了lscut的输出。

组合命令

要在单个命令行上顺序调用几个命令,用分号隔开它们:

→ command1 ; command2 ; command3

要运行一连串的命令,如果有任何一个失败就停止执行,用&&(“和”)符号隔开它们:

→ command1 && command2 && command3

要运行一连串的命令,只要有一个成功就停止执行,用||(“或”)符号隔开它们:

→ command1 || command2 || command3

引用

通常情况下,Shell把空格简单地视为命令行上单词的分隔符。如果你想让一个单词包含空格(例如,一个带空格的文件名),就用单引号或双引号把它括起来,这样Shell就会把它当成一个整体。单引号会原样处理它们的内容,而双引号则让Shell结构(例如变量)可以被求值:

→ echo '变量HOME的值是 $HOME'
变量HOME的值是 $HOME
→ echo "变量HOME的值是 $HOME"
变量HOME的值是 /home/smith

反引号(``)会使它们的内容被视为Shell命令进行求值。内容会被替换为命令的标准输出:

→ date +%Y           打印当前年份
2023
→ echo 今年是 `date +%Y`
今年是 2023

美元符号和括号等同于反引号:

→ echo 今年是 $(date +%Y)
今年是 2023

但是它们优于反引号,因为它们可以被嵌套使用:

→ echo 明年是 $(expr $(date +%Y) + 1)
明年是 2024

转义

如果一个字符对于Shell来说具有特殊含义,但你希望它被原样使用(例如,*作为实际的星号而不是通配符),那么就在该字符前加上反斜线“\”字符。这就叫做转义特殊字符:

→ echo a*        作为通配符,匹配“a”开头的文件名
aardvark  adamantium  apple
→ echo a\*                  作为实际的星号
a*
→ echo "我住在 $HOME"    打印变量的值
我住在 /home/smith
→ echo "我住在 \$HOME"   一个实际的美元符号
我住在 $HOME

你也可以转义控制字符(制表符、换行符、^D等),以便它们在命令行中被原样使用,如果你在它们前加上^V。这对于制表符尤其有用,因为Shell否则会用它们进行文件名补全。

→ echo "这里和这里之间有一个制表符^V    "
这里和这里之间有一个制表符

命令行编辑

Bash允许你编辑你正在操作的命令行,使用的快捷键受到了文本编辑器emacs和vi的启发(参见[“文件创建和编辑”])。要启用emacs键的命令行编辑,运行此命令(并把它放在你的*~/.bash_profile*中使其永久生效):

→ set -o emacs

对于vi(或vim)键:

→ set -o vi

emacs键盘操作vi键盘操作 (按ESC后)意义
^P 或 上箭头k转到前一条命令
^N 或 下箭头j转到下一条命令
^R
交互式地搜索前一条命令
^F 或 右箭头l向前移动一个字符
^B 或 左箭头h向后移动一个字符
^A0转到行首
^E$转到行尾
^Dx删除下一个字符
^U^U清除整行

命令历史

你可以回顾你之前运行过的命令,即Shell的历史记录,并重新执行它们。一些有用的与历史记录相关的命令如下:

命令含义
history打印你的历史记录
history N打印你历史记录中最近的 N 条命令
history -c清除(删除)你的历史记录
!!重新执行上一条命令
!N重新执行你历史记录中编号为 N 的命令
!-N重新执行你输入的 N 条命令前的命令
!$代表上一条命令的最后一个参数;在执行可能会损坏操作的命令之前,检查文件是否存在,例如删除它们:→ **ls z*** zebra.  zookeeper → **rm !$**  等同于 "rm z*"
!*代表上一条命令的所有参数:→ **ls myfile emptyfile hugefile** emptyfile  hugefile  myfile → **wc !***      18      211     1168 myfile       0        0        0 emptyfile  333563  2737539 18577838 hugefile  333581  2737750 18579006 total

文件名补全

在输入文件名的过程中,按下Tab键,Shell会自动为你补全(完成输入)文件名。如果有几个文件名符合你到目前为止输入的内容,Shell会发出蜂鸣声,表明匹配是模糊的。立即再按Tab键,Shell会提供选择项。试试看:

→ cd /usr/bin
→ ls un<Tab><Tab>

Shell将显示 /usr/bin中所有以 un 开头的文件,如 uniq 和 unzip。输入几个更多的字符以消除你的选择的模糊性,然后再按Tab键。

Shell job控制

jobs列出你的作业.
&在后台运行一个作业.
^Z暂停当前的(前台)作业.
suspend暂停一个Shell.
fg恢复一个作业:将它带到前台.
bg让一个被暂停的作业在后台运行.

所有Linux shell都有作业控制功能:能够在后台(在幕后进行多任务处理)和前台(作为你Shell提示符的活动进程运行)运行命令的能力。一个作业就是Shell的工作单位。当你交互式地运行一个命令时,你当前的Shell将它视为一个作业。当命令完成时,相关联的作业就消失了。作业比Linux进程的级别更高;Linux操作系统对它们一无所知。它们只是Shell的构造。以下是关于作业控制的一些重要词汇:

  • • 前台作业在Shell中运行,占用Shell提示符,所以你不能运行另一个命令

  • • 后台作业在Shell中运行,但不占用Shell提示符,所以你可以在同一个Shell中运行另一个命令

  • • 暂停临时停止一个前台作业

  • • 恢复使一个被暂停的作业再次在前台运行

jobs

内置命令 jobs 列出你当前Shell中运行的作业:

→ jobs
[1]-  正在运行        emacs myfile &
[2]+  已停止         ssh example.com

左边的整数是作业号,加号标识默认受 fg(前台)和 bg(后台)命令影响的作业。

&

放在命令行的末尾,& 让给定的命令作为一个后台作业运行:

→ emacs myfile &
[2] 28090

Shell的回应包括作业号(2)和命令的进程ID(28090)。

^Z

在Shell中输入 ^Z,当一个作业在前台运行时,将暂停该作业。它只是停止运行,但它的状态被记住了:

→ sleep 10        等待10秒
^Z
[1]+  已停止          sleep 10

现在你已经准备好输入 bg 把命令放到后台,或者 fg 在前台恢复它。你也可以让它暂停并运行其他命令。

suspend

内置命令 suspend 会尽可能暂停当前的Shell,就像你对Shell本身输入了 ^Z。例如,如果你用 sudo 命令创建了一个超级用户Shell,并想要返回到你原来的Shell:

→ whoami
smith
→ sudo bash
Password: *******# whoami
root
# suspend
[1]+  已停止         sudo bash
→ whoami
smith

bg

bg [%jobid]

内置命令 bg 将一个被暂停的作业发送到后台运行。如果没有参数,bg 操作最近被暂停的作业。要指定特定的作业(由 jobs 命令显示),提供一个百分号前面的作业号:

→ bg %2

有些类型的交互式作业不能保持在后台运行,例如,如果它们正在等待输入。如果你试图这样做,Shell将暂停作业并显示:

[2]+  已停止     命令行在此

现在你可以恢复作业(使用 fg)并继续。

fg

fg [%jobid]

内置命令 fg 将一个被暂停或后台运行的作业带到前台。如果没有参数,它选择一个作业,通常是最近被暂停或后台运行的一个。要指定特定的作业(如 jobs 命令所示),提供一个百分号前面的作业号:

→ fg %2

同时运行多个Shell

job允许你同时管理多个命令,但是一次只能有一个在前台运行。更强大的是,你也可以同时运行多个shell,每个shell都有一个前台命令和任意数量的后台命令。

如果你的Linux计算机运行的是如KDE或Gnome这样的窗口系统,你可以通过打开多个shell窗口同时轻松运行多个shell。此外,某些shell窗口程序,如KDE的konsole,可以在一个窗口中打开多个标签页,每个标签页都运行一个shell。

即使没有窗口系统——比如,通过SSH网络连接——你也可以同时管理多个shell。screen程序使用普通的ASCII终端来模拟多个窗口,每个窗口都运行一个shell。使用特殊的按键,你可以随意从一个模拟窗口切换到另一个。(tmux就是另一个这样的程序。)要开始一个screen会话,只需运行:

→ screen

你可能会看到一些介绍性的信息,然后就是你的普通shell提示符。看起来好像什么都没发生,但是你现在已经在一个虚拟的“窗口”内运行了一个新的shell。screen程序提供了10个这样的窗口,标签从0到9。

输入一个简单的命令,如ls,然后按^A^C(control-A,control-C)。屏幕会清空,并显示一个新的shell提示符。你实际上是在查看第二个独立的“窗口”。运行一个不同的命令(比如df),然后按^A^A,你就会切换回第一个窗口,在那里你的ls输出现在再次可见。再次按^A^A就可以切换回第二个窗口。以下是一些常用的screen按键(查看manpage或键入^A?获取屏幕帮助):

^A?帮助:显示所有按键命令。
^A^C创建一个窗口。
^A0^A1 ... ^A9切换到窗口0到9,依次类推。
^A'提示输入一个窗口编号(0-9),然后切换到它。
^A^N数字上切换到下一个窗口。
^A^P数字上切换到前一个窗口。
^A^A切换到最近使用过的另一个窗口(在两个窗口之间切换)。
^A^W列出所有你的窗口。
^AN显示当前窗口编号。(注意,N是大写的。)
^Aa向你的shell发送一个真正的control-A,被screen忽略。在bash中,control-A通常将光标移动到命令行的开始。(注意,第二个a是小写的。)
^D结束当前的shell。这是普通的“文件结束”按键,解释在[“终止一个Shell”],可以关闭任何shell。
^A\杀掉所有窗口并终止screen

screen窗口中运行文本编辑器时要小心。screen会捕获所有你的control-A按键,即使它们是作为编辑命令的。键入^Aa将真正的control-A发送给你的应用程序。

终止正在进行的命令

如果你从前台运行的shell启动了一个命令,并想立即终止它,可以输入^C。shell会识别^C为“立即终止当前前台命令”。所以,如果你正在显示一个非常长的文件(比如,使用cat命令),并想停止,输入^C

→ cat hugefile
Lorem ipsum dolor sit amet, consectetur adipiscing
odio. Praesent libero. Sed cursus ante dapibus diam.
quis sem at nibh elementum blah blah blah ^C

要终止在后台运行的程序,你可以用fg将其带到前台,然后输入^C

→ sleep 50 &
[1] 12752
→ jobs
[1]-  Running       sleep 50 &
→ fg %1
sleep 50
^C

或者,你也可以使用kill命令(参见[“控制进程”])。

在被杀掉后的程序

^C杀掉前台程序可能会让你的shell处于奇怪或无响应的状态,可能不会显示你输入的按键。这是因为被杀掉的程序没有机会清理自己的环境。如果这种情况发生,你可以:

  1. 1. 按^J来得到一个shell提示符。这个按键产生的字符与Enter键(新行)相同,但即使Enter键不工作,它也会工作。

  2. 2. 输入shell命令reset(即使你输入时字母不显示),然后再次按^J来运行这个命令。这应该可以将你的shell恢复正常。

输入^C并不是一个友好的结束程序的方式。如果程序有自己的退出方式,尽可能使用那个(参见前面的侧边栏获取详细信息)。

^C只在shell中起作用。如果在非shell窗口的应用程序中输入,可能不会有任何效果。此外,一些命令行程序被编写成“捕获”^C并忽略它:一个例子是文本编辑器emacs。

终止一个Shell

要终止一个shell,可以运行exit命令或者输入^D

→ exit

定制Shell行为

要配置所有的shell以特定的方式工作,编辑你的家目录中的*.bash_profile* 和 .bashrc 文件。每次你登录(~/.bash_profile)或打开一个shell(~/.bashrc)时,这些文件都会执行。它们可以设置变量和别名,运行程序,打印你的星座,或者你喜欢的任何事情。

发表评论

快捷回复: 表情:
aoman baiyan bishi bizui cahan ciya dabing daku deyi doge fadai fanu fendou ganga guzhang haixiu hanxiao zuohengheng zhuakuang zhouma zhemo zhayanjian zaijian yun youhengheng yiwen yinxian xu xieyanxiao xiaoku xiaojiujie xia wunai wozuimei weixiao weiqu tuosai tu touxiao tiaopi shui se saorao qiudale qinqin qiaoda piezui penxue nanguo liulei liuhan lenghan leiben kun kuaikule ku koubi kelian keai jingya jingxi jingkong jie huaixiao haqian aini OK qiang quantou shengli woshou gouyin baoquan aixin bangbangtang xiaoyanger xigua hexie pijiu lanqiu juhua hecai haobang caidao baojin chi dan kulou shuai shouqiang yangtuo youling
提交
评论列表 (有 0 条评论, 904人围观)

最近发表

热门文章

最新留言

热门推荐

标签列表