《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
- …
- grep - 基本的grep命令是 grep
- 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}
- var=${str:-default} ,含义是如果str字符串存在且不为空则将var赋值为str,否则将str和var都赋值为default,有时候只想检查str并确保为其赋值,此时可以省略var,并且为了确保shell不将结果当作命令执行,可以将 var= 替换为 : ,如下
- 常用环境变量
- 判断命令
- test 和 [ ] 是等价的,可以将 [ ] 看作是两条命令,分别表示条件的起始和终止,因为是命令,因此必须使用空格分隔;
- 经常会把被判断的变量用引号括起来,这是为了在变量为空或没设置时,避免shell执行报错,例如 [ $a=$b ],如果a是空字符串,在shell看来就是 [ =bbb ],这是一个不合法的命令;
- shell中其实不存在true/false,判断一般认为true是真的,但在shell中true是0的代名词,因为return 0表示成功,因此后面介绍的控制语句命令在结果是0时进入true对应的条件;
- 针对文件的判断
- test 和 [ ] 是等价的,可以将 [ ] 看作是两条命令,分别表示条件的起始和终止,因为是命令,因此必须使用空格分隔;
- 针对数值的判断
- 针对字符串的判断
- 控制语句
- 条件判断: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…:具体参数变量
- shell函数声明:funName() {…},函数不需要声明参数,参数通过预定义的参数变量取得
- 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,就不说了;