wtf is wtf?

wtf是一个linux里的一个指令,在bsdgames包里。使用之前要用sudo apt install bsdgames下载一下这个包。

他的作用是告诉你一个术语是什么意思。比如你碰到了lol,但是你不知道是什么意思,你就可以输入wtf is lol

如果输入wtf is wtf呢?

他会很正经地告诉你:WTF: {what,where,who,why} the fuck

wtf里有什么

我们来看看这个指令怎么实现的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#!/bin/sh
# Automatically generated from wtf/wtf.in. Do not edit.
#!/bin/sh
#
# $NetBSD: wtf,v 1.11 2003/04/25 19:08:31 jmmv Exp $
#
# Public domain
#

usage() {
echo "usage: `basename $0` [-f dbfile] [-t type] [is] <acronym>"
exit 1
}

acronyms=${ACRONYMDB:-/usr/share/games/bsdgames/acronyms}

args=`getopt f:t: $*`
if [ $? -ne 0 ]; then
usage
fi
set -- $args
while [ $# -gt 0 ]; do
case "$1" in
-f)
acronyms=$2; shift
;;
-t)
acronyms=/usr/share/games/bsdgames/acronyms.$2; shift
;;
--)
shift; break
;;
esac
shift
done

if [ X"$1" = X"is" ] ; then
shift
fi

if [ $# -lt 1 ] ; then
usage
fi

if [ ! -f $acronyms ]; then
echo "`basename $0`: cannot open acronyms database file \`$acronyms'"
exit 1
fi

rv=0
while [ $# -gt 0 ] ; do
target=`echo $1 | tr '[a-z]' '[A-Z]'`
ans=`fgrep $target < $acronyms 2>/dev/null \
| sed -ne "\|^$target[[:space:]]|s|^$target[[:space:]]*||p"`
if [ "$ans" != "" ] ; then
echo "$target: $ans"
else
ans=`whatis $1 2> /dev/null | egrep "^$1[, ]" 2> /dev/null`
if [ $? -eq 0 ] ; then
echo "$1: $ans"
else
echo "Gee... I don't know what $1 means..." 1>&2
rv=1
fi
fi
shift
done
exit $rv

[]表示可选,<>表示必选

[-t type]表示-t后面要跟着个类型,比如wtf -t internet is TCP,然而这个type似乎需要另外安装数据库才能使用。我的默认type只有comp,所以只能搜索comp类型的。路径是${ACRONYMDB:-/usr/share/games/bsdgames}

args= `getopt f:t: $*` 中的反引号表示运行中间的内容,同时将返回的字符传给前面的变量,也就是args。那我们就要了解getopt的作用是什么。只着眼于目前的用法,f:t:表示-f和-t后面需要有参数,并且将当前指令“格式化”。比如在终端中输入

1
2
huaziqi@LAPTOP:/mnt/c/Users/huaziqi$ getopt f:t: is -t type -f file jj
-t type -f file -- is jj

它会将参数全部放在--前面,这样就方便后续的处理。那+一个数字或者符号通常表示一个特殊的含义,后面代码里也会碰到不少。$*表示除了wtf后面的所有参数,毕竟这个wtf现在已经没什么用了。

if [ $? -ne 0 ]; then这一句中有两个点:$?表示什么,-ne表示什么?

&?表示上一个指令返回的参数。上一个指令是哪一个?其实就是那个getopt指令,``直接会把括在里面的内容运行起来。如果运行完全没有问题,他就会返回一个0,如果返回的不是0,那就表示运行时出现了一些问题。可以尝试一下在bash中运行getopt f:t: -f oo -t他会显示运行错误,再输入echo $?会输出1而不是0,输入正确的指令再输出$?就是0了。

运行错误就说明指令出错,就会调用usage,然后exit 1这个1应该就表示这个指令运行错误的参数,存储在$?中。

-ne是not equal的缩写,equal就是-eq,greater than就是-gt,还有-ge,有点像汇编里的跳转指令。

set -- $args指令表示将当前参数的顺序设置为args里的。args中的参数顺序是经过getopt重排过的。如果不执行的话,参数顺序就是

1
2
3
4
5
$0 = wtf
$1 = -t
$2 = internet
$3 = is
$4 = tcp

is也可能放在前面$1,执行过后的顺序是这样的

1
2
3
4
5
6
$0 = wtf
$1 = -t
$2 = internet
$3 = --
$3 = is
$4 = tcp

这里有一个细节就是$0是不会变的。首先set --指令不会设置 1开始设置的。其次1=-t开始一个一个重新设置参数,方便后续处理。

还有一个细节是关于这个脚本名的。观察到$0 = wtf,那么basename $0中的basename似乎没什么用?并非如此。因为大多数情况下用户输入的都是wtf,所以$0也是wtf,但是用户也可以输入一个完整的路径名,比如/usr/local/bin/wtf,那么这时候就需要用到basename了。平时我们用的wtf也只是提前写在环境变量中,bash才知道具体的路径。

再往下看,先了解一下case的用法:

1
2
3
4
5
6
7
8
9
10
11
case 变量 in
模式1)
命令序列1
;;
模式2)
命令序列2
;;
*)
默认命令
;;
esac

*)表示其他情况,esac表示case的结束,其实就是倒过来写的case。然后每一种情况要使用单行的两个;结束。

在代码中,我们还看到了其他很多的;,那么什么时候要用到 ; ?gpt说,如果一行出现了两个指令,此时就需要;来分隔。比如说:

1
2
3
4
if []
then
指令
fi

或者

1
2
3
if []; then
指令
fi

大概就是这样。因为这一行中既有if又有then,所以要使用;分隔。

while [ $# -gt 0 ]; do while的条件是参数数量大于0。$#就表示参数数量,后面的shift表示