Shell 学习笔记 0x03

Shell 学习笔记 0x03

RayAlto OP

1. 一些很酷的文本格式化工具

1.1. nl

添加行号:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ echo 'foo\nbar\n\nwhat\nthe\n\nfuck\n?!'
foo
bar

what
the

fuck
?!
$ echo 'foo\nbar\n\nwhat\nthe\n\nfuck\n?!' | nl -ba -nrz -w3 -s' ' -
001 foo
002 bar
003
004 what
005 the
006
007 fuck
008 ?!
  • -ba: body numbering ,设置为 all ,为所有行(包括空行)添加行号
  • -nrz: number format ,设置为 right justified with leading zeros ,右对齐并用 0 填充
  • -w3: number width ,设置为 3
  • -s' ': number separator ,设置为 ,行号与正文之间放一个空格

1.2. fold

限制行宽,比如 clang-format 好像是限制一行最多 80 个字符,可以像这样实现:

1
fold -w80 -s < main.cc > main.folded.cc

1.3. fmt

更高级的格式化工具,刚才用 fold 处理 C++ 代码可能会产生问题,比如一行注释超过了 80 宽, fold 会直接把超过的部分放在新的一行,但不会加上 // ,这时 fmt 可以有更好的实现:

1
fmt -w80 -p'// ' main.cc > main.fmted.cc

1.4. printf

跟 C 的差不多:

1
2
3
4
$ printf 'He%dlo W%drld\n' 1 0
He1lo W0rld
$ printf '%#06x\n' 255
0x00ff

2. Bye World

为啥都是 Hello World 呢,一般输出这句话程序不就退出了吗?那不应该输出 Bye World 吗?

1
2
3
#!/bin/sh

echo 'Bye World' # 永别了,世界

第一行 #!/bin/shshebang #! 后面接这个脚本的解释器, /bin/sh 表示系统默认的 Shell ,在我的 ArchLinux 下是 /bin/bash 的 symbolic link ,在我的 Debian 下是 /bin/dash 的 symbolic link ,所以我觉得写 #!/bin/sh 更加通用

2.1. PATH

我给 ~/.local/bin 放进了我的 PATH 里了,修改了 rc 文件后可以用 built-in command ./source 来重新加载:

1
2
. .zshrc
source .zshrc

2.2. 折行

如果一行写不下可以用 line continuation (行继续符)来折行:

1
2
3
4
5
6
7
#!/bin/sh

command -option1 param1 \
-option2 param2 \
-option3 param3 \
-option4 param4 \
-option5 param5

使用 "" 包围的字符串可以包含换行:

1
2
3
4
5
#!/bin/sh

echo "line1
line2
line3"

2.3. 变量

跟 Python 一样, Shell 也可以随便声明一个变量:

1
2
3
4
#!/bin/sh

foo="bar"
echo $foo

Shell 在执行 echo $foo 时会先展开 $foo"bar" ,实际上执行的是 echo "bar" ,如果执行时某个变量没有定义,可能会导致一些问题,比如:

1
2
3
4
5
#!/bin/sh

dir1="foo"
dir2="bar"
mv $dir1 $dir3

会导致 Shell 实际执行 mv foo ,少了一个参数, mv 会报错。可以用 {} 包围变量名:

1
2
3
4
5
#!/bin/sh

dir1="foo"
dir2="bar"
mv $dir1 ${dir2}.dir

实际上执行的指令则为 mv foo bar.dir

Shell 中为变量赋值的 = 两边不能有空格,因为空格默认被视为分隔符, foo = bar 会被视为执行指令 foo 并带上参数 =bar

2.4. Here Document

1
2
3
4
5
6
#!/bin/sh

cat << EOF
line 1
line 2
EOF

脚本会输出

1
2
line 1
line 2

<< 后面接一个语句(可以进行求值),这个语句的结果将会作为末尾的标志,换行后可以输入任意内容,直至末尾的标志单独地出现在一行(开头和结尾都没有多余的空格),比如上面的就用 EOF 作为末尾的标志,两个 EOF 之间的内容就会被放进 cat 的 stdin 里(可以通过 n<<

再比如:

1
2
3
4
5
6
7
#!/bin/sh

foo=114514

cat << EOF
$foo
EOF

会输出:

1
114514

使用 <<- 可以忽略后面每行用于格式化的 \t (只忽略 \t ,其他空字符不算):

1
2
3
4
cat <<- EOF
foo
bar
EOF

输出:

1
2
foo
bar

2.5. 函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function foo {
echo foo
return
}

bar () {
echo bar
return
}

function baf () {
echo baf
return
}

都可以是函数的定义,可以像这样直接调用:

1
2
3
foo
bar
baf

或者展开:

1
echo "$(foo) $(bar) $(baf)"

2.6. 局部变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/bin/sh

foo () {
local a
echo ${a}
a=foo
echo ${a}
return
}

bar () {
echo ${a}
local a=bar
echo ${a}
return
}

foo
bar

输出:

1
2
3
4

foo

bar