《Linux程序设计》的读书笔记。

Linux环境基础

目录

在Linux环境中,我们常用shell来执行各种命令,这些命令可以是脚本,也可以是编译好的C程序或其他语言编译好的程序,在作为用户的我们看来这些程序都是一样的。在输入命令后,shell会从一组指定的目录中寻找对应的程序,通过PATH环境变量指定要搜索的目录,默认/bin, /usr/bin, /usr/local/bin都会在搜索路径中,其中:

  • /bin 用于存放系统启动时所需要的程序
  • /usr/bin 用户使用的标准程序
  • /usr/local/bin 本地程序,用户安装的程序放在这,此外 /opt 目录也常用于存放安装的程序

特别的,root用户的PATH目录中还包含/sbin 和 /usr/sbin,这里面有一些需要特权才能使用的程序。

C编译器

Linux系统中的cc、gcc、c89都是C编译器,指向系统的c编译器。历史上C编译器被简称为cc,Linux提供的C编译器为GNU开源编译器,叫gcc,在Linux系统上cc就是gcc。
gcc常用的编译选项包括:

  • -l和-L用于指定链接库及其路径
  • -I用于指定头文件搜索路径
  • -c, -S, -E 分别表示仅编译、仅汇编、仅预处理
  • -f 表示flag参数,常用的是-fpic
  • -m 表示mode
    • -march 指定编译产物最低运行的处理器系列,能够在所有兼容该系列的处理器上运行
    • -mfloat-abi ARM平台会用到,用于指定编译产物能够使用什么方式来做浮点计算
  • -arch 表示构建产物的目标机器

shell

使用man工具

使用man随时查询命令的格式非常重要,不同的发行版对同一个命令会有不同的选项,开发者很难记住所有机器的所有命令的所有选项,需要时才会用man查询:man [section]

基础

  • 常用shell - 目前主流的shell是bash,默认的shell是/bin/sh指向的shell
  • 管道 - 将标准输出作为下一个程序的标准输入
  • 重定向 - 将指定fd重定向到指定文件
    • 默认使用 > 表示对stdout,也就是1的重定向,也可以使用 1> 或者 2> 显式对特定fd进行重定向;
    • 使用 >> 来将内容追加到文件中,而不是直接重建文件再添加内容;
    • 也可以使用比较特殊的写法:2>&1,表示将stderr重定向到stdout,使用这种写法的话必须先确定stdout的目标,一般写成 mycmd > /dev/null 2>&1
  • 常用命令
    • grep - 基本的grep命令是 grep <输入文件…>
    • find
  • shell中,一切都是字符串,有的命令要求其参数是数字,此时作为参数的依然是字符串,是由命令负责将字符串转成数字并执行特定逻辑的,比如test $num -gt $num2
  • shell中,所谓的数组就是用 $IFS 分隔的字符串,$IFS默认是空格、tab和换行,因此任何能够输出由$IFS分隔的字符串的命令的标准输出都可以被用作数组;
  • 文件通配符:* 表示当前目录下的所有文件名,文件名间使用空格分隔
  • 文件类型:Linux中一般不使用后缀表示文件类型,要查看某个文件的类型,需要使用file命令

shell脚本程序

  • 条件赋值
    • var=${str:-default} ,含义是如果str字符串存在且不为空则将var赋值为str,否则将str和var都赋值为default,有时候只想检查str并确保为其赋值,此时可以省略var,并且为了确保shell不将结果当作命令执行,可以将 var= 替换为 : ,如下
      • : ${str:-default}
  • 常用环境变量

屏幕快照 2020-04-28 下午3.43.37.png

  • 判断命令
    • test 和 [ ] 是等价的,可以将 [ ] 看作是两条命令,分别表示条件的起始和终止,因为是命令,因此必须使用空格分隔;
      • 经常会把被判断的变量用引号括起来,这是为了在变量为空或没设置时,避免shell执行报错,例如 [ $a=$b ],如果a是空字符串,在shell看来就是 [ =bbb ],这是一个不合法的命令;
      • shell中其实不存在true/false,判断一般认为true是真的,但在shell中true是0的代名词,因为return 0表示成功,因此后面介绍的控制语句命令在结果是0时进入true对应的条件;
    • 针对文件的判断

image.png

  • 针对数值的判断

image.png

  • 针对字符串的判断

image.png

  • 控制语句
    • 条件判断:if [ ]; then - elif - else - fi
    • for循环:for in ; do - done
    • while循环:while <命令>; do - done
    • until循环:until <命令>; do - done
    • case语句:case in [|…]) ;; … esac
      • pattern部分可以写简单的正则表达式
    • &&和||,不区分优先级,实际使用中若混用应该使用括号明确优先级
    • 语句块:{…} 被当成是一个单独的命令执行,感觉概念上就像立即执行的闭包一样
    • 使用continue或者break可以更好的控制循环
  • 函数
    • shell函数声明:funName() {…},函数不需要声明参数,参数通过预定义的参数变量取得
      • $* , $@:都是参数列表,一般用” “包围,前者所有参数被合并成一个字符串包围在 “” 中返回,后者每个参数各自被 “” 包围,各自是一个字符串
      • $#:参数数量
      • $1, $2…:具体参数变量
  • HEREDOC
    • shell中的heredoc是用两个连续的小于号表示的,后面紧跟着一个标记字符串,在HEREDOC的结尾处也需要使用改标记字符串标记其结束,例如:cat <<!!TAG!! ……. !!TAG!!;
    • 在上面将HEREDOC提供给cat命令时,可以看作HEREDOC被shell包装成了一个流被作为标准输入提供给cat;
  • shell的调试
    • 使用sh执行shell脚本时,可以使用的调试选项包括(这些选项也可以使用set命令设置默认开启或关闭):
    • -n:只检查语法错误,不执行命令
    • -v:在执行命令前回显命令
    • -x:在执行命令后回显命令
    • -u:遇到未定义的变量时打印错误信息
  • 经典命令
    • 冒号在shell中是一个内置命令,作用是返回0,并且会展开后面的表达式;
    • unset var 和 var=”” 在正常情况下没有区别,除非你set -u,禁止访问未绑定的变量
    • 使用 `` 或者 $( ) 可以取得语句执行输出的内容,应该尽量避免反引号,因为普遍认为可读性不如$( )好;
    • 使用 expr 可以进行很多表达式求值运算,不过这个命令会使用单独的expr程序执行,比较慢;
      • 一般使用 $(( )) 执行算术运算,这种写法是直接在当前shell中执行的;
    • 使用 set 可以为shell设置参数变量,使用set设置的变量之后就可以通过 $1, $2 等访问了
    • shift用于将所有参数左移,原本$2参数可以通过$1引用了,以此类推
    • trap用于指定接收到信号后的逻辑,trap ,command可以是一个内容为命令的字符串,当command为 - 时表示恢复原始信号处理逻辑,为 ‘’ 时表示忽略信号
    • find命令很常用,但大多数人都不完全清除它所提供的所有能力,最基础的用法是:find -name ,但实际上,find可以指定的option和test非常多,可以做非常定制化的查找;
  • 正则
    • POSIX规定的正则表达式中明确了诸如 [:digit:] 这样的标记代表数字,像 \d 并不在规范中,不过很多程序还是把这两个标记都看作同样的代表数字的标记;
    • 使用grep时,如果要使用稍微复杂点的正则,都需要加上 -E 选项;

工具

vi

vi个人用的还算比较多,vim也有内置的tutorial,就不说了;

ed

ed不是很常用,这是一个基于行的文本编辑工具。

awk