0%

快乐Linux学习(三)

本文是快乐学习Linux的第三篇,是基于Windows的Linux子系统(WSL)进行操作的。

适用于学习Linux系统中shell特性和键盘操作的读者。

字符展开

每当我们在bash中输入一串命令,bash就会在执行命令之前将命令进行展开操作。

我们可以使用echo来显示一行文本:

1
echo This is a test.

那么不出意外将会输出结果This is a test.,当我们输入:

1
echo *

就会出现意外了😂,结果是根据通配符含义的“*”匹配当前文件夹的任何内容,而不是我们想要打印的“*”,这就意味着我们的命令有了自己的想法,想要按照自身的规则先进行展开成完全态,再执行命令。

路径名展开

以上这样的展开被称为路径名展开,例如打印当前目录所有的以l开头的文件或目录:

1
echo l*

但是无法显示隐藏文件的展开路径,但是办法总比困难多。我们进行尝试:

1
echo .*

几乎成功了,但是存在了不需要的...。换个方法:

1
ls -d .[!.]?* | less

仅展示以.开头,第二个符号不是.,并且至少再包含一个符号,之后可以紧跟任意多个字符。

我们可以发现,对于文件和目录进行打印输出的时候,使用echo和ls的结果似乎差不多,但是细心的话,我们可以发现,ls文件名之间的间距是根据制表符规定的,而echo每两个文件名之间的间距是一个空格,其中原因也是shell的命令展开。

算数表达式展开

算术表达式是形如$((expression)),表达式中不在意空格,并且可以嵌套存在,需要注意的是除法“/”,由于表达式仅支持整数操作,所以除法操作得到的结果是舍尾的整数,想要获得余数可以使用“%”进行操作。

花括号展开

花括号是为了获得多个具有一定重复规律的字符串而出现的,举个例子💡

1
echo hello-{R,G,B}-world

则结果会生成hello-R-world hello-G-world hello-B-world,或者想要生成2019-01至2021-12的文件夹来存放相应内容,可以使用:

1
mkdir {2019..2021}-0{1..9} {2019..2021}-1{0..2}

其中花括号内可以包含字符串列表,整数区间和字符区间,区间使用..来表示区间范围,其中字符区间全部是大写或全部是小写的时候没有任何问题,但是在大写到小写的区间内,由于ASCII码的原因,会存在几个过度的字符,这需要注意一下。

同样的,花括号也可以嵌套

参数展开

参数展开在此处简要体提及,之后会在shell脚本中详细阐述。

我们查看一下可以使用的有效参数:

1
printenv | less

这些参数可以使用 $符号进行调用,来显示参数对应的值:

1
echo $USER

命令替换功能也能将命令的输出作为一个展开模式来使用,例如将找到cp目录的结果作为展开的参数给ls进行打印:

1
ls -l $(which cp)

同样的,管道线也适用参数展开,在旧版bash中也可以使用ls -l `which cp`达到同样效果。

引用

这里的引用指的是一种引用机制,用来有选择的禁止不需要的展开。什么叫做不需要的展开,如下:

1
echo This is a     Test

但是结果是This is a Test,中间想要的空格被自动展开后再进行单词分割(空格、制表符、换行符等界定符)而失去了。再比如:

1
echo The total price is $100.00

但是结果却是The total price is 00.00,原因是$1被视作名为变量1的参数。

为了禁止这些不需要的展开,所以出现了引用机制,这里有两种类型,一种是双引号,一种是单引号

使用双引号的时候,shell使用的一些特殊字符将会失去其特殊含义,单词分割,路径名展开,波浪线展开(用户名)和花括号展开都会被禁止。

例如这个存在空格的破损文件名word count.txt,正常情况下ls的时候会认作两个参数,而使用双引号的时候就会关闭单词分割,从而视作一个参数来正确读取,并且可以使用mv进行重命名。

1
2
ls -l "word count.txt"
mv "word count.txt" word_count.txt

再比如打印日历:

1
echo $(cal)

这就是被单词分割的后果!可以尝试加上双引号,一下子好看了有木有😆

但是对于$,\和`并不会被禁止,也就是意味着参数展开,算术展开和命令替换仍然会被执行。

这就需要使用单引号来禁止全部展开,通过以下对比进行说明:

1
2
3
echo text ~/.txt {a,b} \$100 $(echo ~) $((2+2)) $USER `which cp`
echo "text ~/.txt {a,b} \$100 $(echo ~) $((2+2)) $USER `which cp`"
echo 'text ~/.txt {a,b} \$100 $(echo ~) $((2+2)) $USER `which cp`'

对于转义字符“\”有一个很有趣的东西,echo加上-e能够解释转义字符,例如,10秒后响铃

1
sleep 10; echo -e "Time's up \a"

键盘的高级操作

这里再附带说一下键盘有关的高级操作,命令行的目标是懒惰,各种简短而丰富的命令是为了更少的敲击键盘和无需使用鼠标,来专注于工作本身。

在命令行中存在很多的按键,来快速编辑,例如:

按键 作用
Ctrl-a 光标移动到行首
Ctrl-e 光标移动到行尾
Alt-f 光标向前移动一个字
Alt-b 光标向后移动一个字
Ctrl-l 清空屏幕,与clear相同
Alt-l 光标至字尾的字符转化为小写字母
Alt-u 光标至字尾的字符转化为大写字母

自动补全

自动补全是shell一个很方便的方法,Linux系统不一样可能机制不同,WSL中是只有一个匹配的则敲击一下tab键即可,存在多个匹配条件,则连续敲击两下tab键显示。

历史命令

使用上下键就可以浏览之前输入过的历史命令,不过还可以使用history进行查看:

1
history | less

在每个历史命令中,每行会有一个序号,我们在命令行直接输入!80就可以直接执行第80行的命令了。

使用Ctrl-r可以进入搜索模式,输入部分命令内容,继续按下Ctrl-r就可以从现在过去进行历史命令匹配了。

个人收获

总之,Linux中的shell是一个很有趣的事物,准确的理解其中展开和引用机制可以很好的发挥shell的能力。对于最后提及的键盘快捷键,暂时来说只是锦上添花,更多的还是关注命令本身。

------ 本文结束------