Linux & Shell Scripts 入门

之前用 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 or CRTL + 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 installapt-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 即可

Basic operations with CLI
  • 环境变量:环境变量本身就是一系列特定的字符串,其可以被一个或多个程序访问以实现特定的目的,在 Linux 中可以通过 setenvexport 来查看已有的环境变量设置。最常用的一个环境变量是 PATH,其内容为一系列顺序排列的路径,程序在运行时会依次的在这些路径中寻找所需的文件,可以通过 echo $VARIABLE 来查看环境变量中的内容

  • 文档访问:Linux 配置了非常强大的文档系统,可以通过man -f command_name 来访问程序的文档系统,其替代方法还包括 info command_namecommand_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 在一起显示,还可以联合 >>> 来复制和添加文件中的内容到新的文件中。当被读取的文件过长时,可以采用 headtail 来显示前后10行的内容,或者采用 less filenamecat filename | less 来分页显示。除 catecho commands [strings] 也常被用作打印后续命令的输出结果,和环境变量查询显示,如 echo $PATHecho $HOME

  • 文件生成catecho 也常用于在命令行中直接生成文本文件,如 cat file1 file2 > newfile.txtcat > newfile.txt 创建一个新文件,后续输入的每一行会被自动添加到文件中,直到 ctrl + D 终止,之后如果还想继续添加可以输入 cat >> newfile.txt 完成。对应的执行相同操作的 echo 命令如下:echo line1 > some_fileecho line2 >> some_fileecho line3 >> some_file

  • 文件更新touch file_name 可以创建新文件或者更改已有文件的时间戳

  • 文件传输:在 Linux 下如果需要执行较大的文件下载或者多个相互链接的文件的连续下载,推荐使用这个命令 wget <url>,对于两台主机之间的加密文件传输可以使用 scp local_file user@remote_system: /directory 来完成

  • 压缩文件:针对压缩文件,上述文件操作命令还有一个对应的压缩文件版本,如 zcatzlesszgrepzdiff,具体使用语法与相应的命令相同: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 中表达式可以通过 exprlet 命令来定义,但一个比较推崇的书写方式是 $((...))

  • 字符串操作:在 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 中类似,都可以遍历一个固定长度的列表中的数值,并对这些数值进行操作,但在操作前后需要用 dodone 来完成

    #!/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 -xset +x 命令包含起来

  • 临时文件:可以采用 TEMP=$(mktemp /tmp/tempfile.XXXXXXXX) 来创建临时文件 和 TEMPDIR=$(mktemp -d /tmp/tempdir.XXXXXXXX) 来创建临时目录

参考阅读

  1. 理解 Linux 的硬链接与软链接 - IBM DeveloperWorks

  2. Linux cat command

  3. 开始你的 bash/shell 脚本编程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259