之前用 AWS 做计算的时候临阵磨枪地接触到了一些 Linux 的命令,但这种现学现卖的方式学到的终究都是只言片语,一直想花时间来了解一下为什么 Linux 在代码世界中具有这样不凡的地位。这段时间刚好有些空闲,决定系统的学习一下。找了半天资料之后,在 edX 上找到了 Linux Fundation 官方制作的 Introduction to Linux 这门课,由传奇的 Linus 本人亲自作序,内容非常的全面,是一个系统的熟悉 Linux 的好方式。
作为人类历史上最著名和最大规模的开源项目(没有之一),Linux 几乎遍布在世界上所有 IT 技术可以触及到的领域,小到手机、开发板,大到航天飞机、大型机、数据中心,基于 Linux 内核的不同版本的 Linux 系统都在背后默默支持着环境的稳定运行,单凭这一点,Linux 就值得每一个技术工作者去学习和了解。
很多知识作为静态的信息,在有一定程度的了解之前很容易先入为主的给予一些偏见。但当你投入一定的时间对其进行深入理解之后,就会发现自己之前的观念是错误甚至是愚蠢的。之前一直以为 Linux 的命令行 command line 是一个玄学,但这两天开始了这个系列的课程之后,才顿悟图形界面 Graphic User Interface, GUI 只是人机交互的一种(我承认我智商低,反应慢),而不一定所有场景(例如开发板)都可以(需要)实现 GUI 的支持,在这些场合下,Command Line Interface, CLI 就大有裨益了。
Graphical user interfaces make easy tasks easier, while command line interfaces make difficult tasks possible.
Graphic User Interface, GUI 交互
在图形界面交互的设计方面,由于最终都会依从人类本能的使用习惯,各个系统之间的差异并不大,因此对于熟悉 Windows 系统的人来说带有 GUI 的 Linux 系统非常容易上手。在这里仅记录一些快捷键和命令,以备后续查询使用:
- lock screen:
SUPERUSER + L
- view location:
CRTL + L
- find something:
CRTL + F
- view files with icons or list formats:
CRTL + 1
orCRTL + 2
- show hidden:
CRTL + H
Command Line Interface, CLI 交互
对于 CLI 交互来说,与其死记硬背那些命令,不如理解这些命令的由来,以及其对应的英文单词原意,这样无论对于记忆还是理解这个命令都非常有帮助,在此基础上慢慢熟悉起来就好。例如:
-
在 Linux 下最常用的终端 bash 指代的是 Bourne Again Shell,是对早期的 Steve Bourne 版本的 sh shell 的一个升级和致敬
-
对于 Debian 系列的系统来说,底层的软件安装的管理都归属于
dpkg
,其对应的英文单词为debian pakage
,而对应的更高级别的软件管理系统则是apt
,也即 advanced package tools,对应的安装和搜索文件的命令为apt-get install
和apt-cache search
理解命令行命令的另外一个好处是这些常用的命令在很多编程语言的函数设计中都作为函数的名称或名称的一部分,因此也可以促进其他编程语言的学习。
Most input lines entered at the shell prompt have three basic elements:
- Command
- Options
- Arguments
The command is the name of the program you are executing. It may be followed by one or more options (or switches) that modify what the command may do. Options usually start with one or two dashes, for example, -p or --print, in order to differentiate them from arguments, which represent what the command operates on.
在 Linux 中所有通过 GUI 能够完成的任务都可以通过 CLI 来完成——前提是输入合适的命令。鉴于 Linux 命令众多,这里仅记录一些比较常用但之前不太熟悉的命令和概念:
-
sudo commands
:以 superuser 的身份来执行某个命令 (super user do...) -
远程访问:
ssh
secure shell 是最常用的安全加密访问协议,其背后的加密算法基于 Secure Hashing Algorithms 512 bits, SHA-512,这也是 SSL 等其他加密协议采用的加密算法 -
定位应用程序的位置:
which / whereis app_name
-
定位系统中的文件位置:
locate file_name
,需要注意的是locate
这一命令的执行需要基于一个预先建立好的包含系统中的全部文件的数据库,Linux 系统会默认的每 24 小时执行一次备份,如果想要手动执行可以使用sudo updatedb
命令。另外如果需要更加精确的指定文件中包含的字符,可以通过添加 pipe 来完成:locate file_name | grep some_string
,这里some_string
还可以结合通配符 wildcards 来进一步提高检索能力 -
快速文件的定位:当想要执行小范围的文件查找时,应该采用
find
命令,例如在 /usr 目录下查找文件名为 gcc 的文件:find /usr -type f -name gcc
-
查看当前工作目录:
pwd
(present working directory) -
通配符 wildcards:这里的通配符与 regular expression 中的定义相同,几个常用的通配符如下:
?
匹配任意单个字符,*
匹配任意多个字符,[set]
匹配 set 中的任意一个或多个字符,[!set]
匹配不包含在 set 中的任意一个或多个字符 -
多通道 pipes:在 Linux 和 Unix 系统的命令设计思想中,作者希望能够将多个简短的命令组合在一起来执行复杂的任务,因此设计了多通道这一操作,其实现方式为:
command1 | command2 | command3
,对于多核的 CPU 和具有并行计算能力的硬件来说,不同命令之间不一定需要顺序执行 -
软硬链接:在 Linux 系统内部文件的身份是通过 inode (index node) 号来识别的,如果两个文件共享同一个 inode 号,则将二者之间的关系称作硬链接 hard link。对于已有的一个文件创建硬链接相当于将这个文件复制到了目标目录下,而使得整个文件可以被目标目录共享使用,但同时却只占用一个文件的存储空间。硬链接的创建方式为
ln file_name link_name
;与硬链接相对应的,我们可以通过在ln
命令后添加-s
选项来创建软链接 soft link (symbolic link),软链接的实质可以理解为 windows 下的超链接,通过软链接创建的新文件中的数据内容为原有文件的位置信息 -
创建目录:
mkdir /directory
-
删除操作:
rm -i dirctory
(i: interectively),谨慎使用rm -rf /directory
(rf: remove forcefully),否则可能闯下大祸 -
移动和重命名文件及目录:
mv /directory1 /directory2
,这里需要特别注意mv
既可以完成移动也可以完成重命名操作,当前后两个目录相同而文件名不同时即完成重命名 -
输入和输出:在 Linux 中默认的输入
stdin
的来源是键盘,而默认的输出stdout
是终端,而这些输入和输出的位置可以通过<
和>
来更改 -
定时关机:
sudo shutdown -h 10:00 "routine maintenance."
-
快捷别称:在 Linux 日常使用中,如果某些命令使用的频率较高,则可以通过自定义别称来实现快速执行,例如假设需要经常性的通过
cd
访问一个公共的项目目录cd /home/staff/RandD/projects/projectX/src
则可以通过alias projectX='cd /home/staff/RandD/projects/projectX/src'
来为上述路径切换命令创立一个快捷访问方式,后续只要在 Terminal 中输入projectX
即可
-
环境变量:环境变量本身就是一系列特定的字符串,其可以被一个或多个程序访问以实现特定的目的,在 Linux 中可以通过
set
,env
或export
来查看已有的环境变量设置。最常用的一个环境变量是PATH
,其内容为一系列顺序排列的路径,程序在运行时会依次的在这些路径中寻找所需的文件,可以通过echo $VARIABLE
来查看环境变量中的内容 -
文档访问:Linux 配置了非常强大的文档系统,可以通过
man -f command_name
来访问程序的文档系统,其替代方法还包括info command_name
或command_name --help
-
文件属性:在 Linux 中文件的扩展名不像在 Windows 下那样对于文件的类型具有确定性,也即
file_name.txt
不一定是文本文件,对此可以通过file file_name
来确认文件的真实属性 -
文件归档:Linux 中常用的文档归档命令
tar
是 tape archive 的缩写,这个应用可以与压缩工具联合使用来将多个文件及目录打包成一个压缩文件或者解压一个压缩文件,例如tar xvf file_name.tar.gz
-
文件备份:除可以使用
cp
命令外,还可以使用rsync
命令,后者会首先检查待备份的文件是否发生改动,并只备份改动的部分,因此更加高效,rsync
另外一个优点是可以实现远程/多机备份 -
文件显示:
cat
一般可以用于显示文本文件内的内容,但当提供多个文件名时可以将两个文件内的容用连接 catenate 在一起显示,还可以联合>
和>>
来复制和添加文件中的内容到新的文件中。当被读取的文件过长时,可以采用head
或tail
来显示前后10行的内容,或者采用less filename
和cat filename | less
来分页显示。除cat
外echo commands [strings]
也常被用作打印后续命令的输出结果,和环境变量查询显示,如echo $PATH
,echo $HOME
-
文件生成:
cat
和echo
也常用于在命令行中直接生成文本文件,如cat file1 file2 > newfile.txt
或cat > newfile.txt
创建一个新文件,后续输入的每一行会被自动添加到文件中,直到ctrl + D
终止,之后如果还想继续添加可以输入cat >> newfile.txt
完成。对应的执行相同操作的echo
命令如下:echo line1 > some_file
,echo line2 >> some_file
,echo line3 >> some_file
-
文件更新:
touch file_name
可以创建新文件或者更改已有文件的时间戳 -
文件传输:在 Linux 下如果需要执行较大的文件下载或者多个相互链接的文件的连续下载,推荐使用这个命令
wget <url>
,对于两台主机之间的加密文件传输可以使用scp local_file user@remote_system: /directory
来完成 -
压缩文件:针对压缩文件,上述文件操作命令还有一个对应的压缩文件版本,如
zcat
,zless
,zgrep
,zdiff
,具体使用语法与相应的命令相同:zcat compressed-file.txt.gz
Shell Scripts
除了逐行的手动在 shell 中输入命令之后,CLI 交互的更强大之处是其可以通过直接运行 Shell Scripts 来执行一系列的任务,也即通过 CLI 运行一段写好的程序。
Features of Shell Scripts-
在 Linux 中 Scripts 文件的开头以
#!/bin/bash
作为第一行,其包含的是即将用于运行文件中的代码的解释器 interpreter 的位置,例如如果即将运行的是Python 代码,则可以将其更改为诸如#!/usr/bin/env python
样式的字符串 -
如果脚本是通过
cat > file_name.sh
来创建的,则需要通过chmod +x file_name.sh
或者chmod 755 file_name.sh
来将其转换成可执行文件 -
通过 shell 运行的命令的返回值可以通过
exit
命令来进行设置,如果需要检验命令是否成功运行,可以通过echo $?
的来查询返回值来进行判断,返回值为0
时代表命令执行成功 -
当命令较长而将其分行放置可以更加便利的理解命令时可以通过
\
来添加分隔,而连接一传顺序执行的命令可以通过;
来完成,如果命令之间存在逻辑关系,则可以用&&
(AND) 或||
(OR) 来代替;
-
在 script 中进行函数定义的语法如下:
function_name () { commands }
-
在 shell 中完整的判断语句语法如下,需要注意的是每一个
if
代码块都需要用fi
来结束#!/bin/bash echo "Enter the first number" read inp1 echo "Enter the second number" read inp2 echo "1. Addition" echo "2. Substraction" echo "3. Multiplication" echo "Please choose a word [1, 2 or 3]? " read oper if [ $oper -eq 1 ] then echo "Addition Result " $(($inp1 + $inp2)) else if [ $oper -eq 2 ] then echo "Substraction Result " $(($inp1 - $inp2)) else if [ $oper -eq 3 ] then echo "Multiplication Result " $(($inp1 * $inp2)) else echo "Invalid Input." fi fi fi
类似的嵌套语句还可以通过
elif
来完成:#!/bin/bash echo "Enter a number:" read count if [ $count -eq 100 ] then echo "The 'count' is 100" elif [ $count -gt 100 ] then echo "The 'count' is greater than 100" else echo "The 'count' is less than 100" fi
-
表达式:在 shell 中表达式可以通过
expr
或let
命令来定义,但一个比较推崇的书写方式是$((...))
-
字符串操作:在 bash script 中字符串的切片操作命令为
${string:0:n}
,统计字符串长度的命令为${#string}
-
case statement: 当变量的不同取值会使得命令的执行有多个不同的途径时,一个更加简洁的方法是通过
case
语句来取代多重if-then-else-fi
嵌套。在如下示例代码中,每一个不同的字符串配对情形用pattern)
来匹配,并且每一个情形的语句块都要以;;
来结束#!/bin/sh echo "Do you want to destroy your entire file system?" read response case "$response" in "yes") echo "I hope you know what you are doing!"; echo "I am supposed to type: rm -rf /"; echo "But I refuse to let you commit suicide";; "no") echo "You have some common sense! Aborting...";; "y" | "Y" | "YES") echo "I hope you konw what you are doing!"; echo "I am supposed to type: rm -rf /"; echo "But I refuse to let you commit suicide";; "n" | "N" | "NO") echo "You have some common sense! Aborting...";; *) echo "You have to give an answer!";; esac exit 0
-
for 循环:Linux 下的
for
循环语法及功能与 Python 中类似,都可以遍历一个固定长度的列表中的数值,并对这些数值进行操作,但在操作前后需要用do
和done
来完成#!/bin/sh sum=0 for j in 1 2 3 4 5 6 7 8 9 10 do sum=$(( ($sum+$j) )) done echo The sum is: $sum echo The sum of numbers from 1 to n is: 'n*(n+1)/2' echo Check Value = $(( ($j*($j+1))/2 )) exit 0
for
循环与case
联合使用的实例代码如下:#!/bin/bash for filename in $(ls) do # Take extension available in a filename ext=${filename##*\.} case "$ext" in c) echo "$filename : C source file";; o) echo "$filename : Object file";; sh) echo "$filename : Shell script";; txt) echo "$filename : Text file";; *) echo "$filename : Unknown file type / Not processed";; esac done
-
while & until 循环:二者的判断和执行情况类似,但判断条件设置上正好相反
#!/bin/bash n=$1 [ "$n" == "" ] && echo please give a number and try again && exit factorial=1 j=1 while [ $j -le $n ] # until [ $j -gt $n ] do factorial=$(( ($factorial * $j) )) j=$(( ($j+1) )) done echo The factorial of $n, "$n"'!' = $factorial exit 0
-
Debugging:在代码调试阶段可以通过
bash -x ./script_file
以 debug 模式运行 script,或者对于需要调试的代码段用set -x
和set +x
命令包含起来 -
临时文件:可以采用
TEMP=$(mktemp /tmp/tempfile.XXXXXXXX)
来创建临时文件 和TEMPDIR=$(mktemp -d /tmp/tempdir.XXXXXXXX)
来创建临时目录
网友评论