shell-解释器以及集合运算

选择合适的shell

众所周知的linux下有许多不同的shell可供选择,比如作为默认shell的bash,以及我们挚爱的zsh和fish。虽然他们的种类很多,但是都是一个解释器,即把我们在终端输入的命令解释为内核可以理解的东西。而shell也就是作为了一个我们和系统内核沟通的桥梁。

不同种类shell存在一个重要原因就是都有自己的特点,个性化,易于使用。比如zsh就支持个性化配置,可以做的比较好看,fish呢是配置比较简单,但是fish的语法与bash差异太大,所以我没有继续使用。

虽然知道这些,我还是被忽悠了。而且这个问题如果不是经常写shell脚本,就很难发现的一个问题。比如工作中使用的ksh,不是我喜欢这个shell,而是默认就是这个。加上我对shell的数组没有太多的了解,所以问题也就发生了。


之前学过,shell中数组是使用的()来表示的,而且元素之间的分隔是采用的空格。

1
num=(1 2 3 4 5)

但是在ksh中,却可以这样使用

1
num={1,2,3,4,5}

由于语句都是拿来在shell(ksh)中直接进行测试的,表示出来的结果也正确

1
2
3
num={1,2,3,4,5}
echo $num
1 2 3 4 5

所以我就这样写了,还以为shell中数组真的可以这么写,但是我的脚本指定的是bash,而在bash中并不支持这么写

1
2
3
num={1,2,3,4,5}
echo $num
{1,2,3,4,5}

所以总结一下教训就是我们最好是使用bash来进行shell编写,因为它的语法是通用的。还有重要的一点就是如果我们对语法不够清晰,那么在测试的时候,还是要使用bash。

数组问题

现在需要明确的一点就是bash中数组写法就是这么唯一的一种,使用(),另外要表示所有的元素要使用${数组名[@]}或者${数组名[*]}。而使用${数组名}表示的却是第一个元素。虽然知道这个,但是在写的时候还是容易犯错

1
2
3
num=(1 2 3 4 5)
echo ${num[@]}
1 2 3 4 5

比如说要表示一个集合中所有元素就是很容易犯错的地方

集合运算

在写shell的时候很多时候就是要对比数据,那么就是两组数据的对比,比如说我要找出那些在另外一组数据中没有的东西,容易想到的一个方法就是循环去查找

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 现在要找到在b在a中没有的数据,很显然是1
a=(1 2 3)
b=(2 3 4)
#这里在表示a这个数组就很容易错误的表示成$a
for i in ${a[@]}
do
for j in ${b[@]}
do
if [[ $i == $j ]];then
break
else
echo "cannot find $i"
fi
done
done

#运行结果
cannot find 1
cannot find 1
cannot find 1
cannot find 3

这么写有两个问题,一是比如说1在第一轮i的循环中都是找不到的,可是它会输出3次找不到1。第二个问题,即使3存在这个里面,但是在j的第一次循环中,2与3不等,会判断找不到3。

那么既然问题这么多,为何不使用集合运算呢。刚开始我以为是没有集合运算的,因为我也没有在书中看到集合运算的这种操作。但是还真的可以做到,工具就那么几个可是在不同人的手中发挥出来的功能却完全不同。

1
2
3
a=(1 2 3)
b=(2 3 4)
echo ${a[@]} ${b[@]} ${b[@]} | xargs -n1 | sort | uniq -u

没错就是这么简单的一行解决了上面的问题!

下面解释一下为什么这么写:

  • 首先是这个数组中所有元素的表示是一个知识点
  • 那么为什么要写两个b的所有元素,这就是精髓所在了,所以的先介绍一下uniq的用法
    • uniq 不带任何参数表示去重
    • uniq -u 表示找出只出现一次的数据
    • uniq -d 表示重复出现的数据,出现次数>=2
  • 这样就很好理解了,如果仅仅只写一次b数组的所有元素,那么b数组中的4也是符合条件的,它也只出现了一次。那么写两次b数组,既b中所有元素都至少出现了两次,再与a一起进行比较时,除了a中有b中没有的元素外,b中所有元素自动过滤掉了。
  • 如果仅仅知道上面的东西,还是无法写出来,为什么,因为uniq在比较的时候是按行来比较的。而且它只会比较相邻的两行间是否存在重复。这就是为什么使用xargs -n1来将行转为列,以及使用sort进行排序的原因了。

至此集合运算算是说完了,写法比较简单,很容易学习。但是真正的要把集合运算的思想融入编程中,却并不是一朝一夕很够做到的,需要牢记的一点就是集合运算真的是一把利器,用的好,威力无穷。

1
2
3
4
5
6
7
8
9
10
11
12
# 下面是这几中集合的运算
# 并集
echo ${a[@]} ${b[@]} | xargs -n1 | sort | uniq
# 交集
echo ${a[@]} ${b[@]} | xargs -n1 | sort | uniq -d
# 差集
# a差b
echo ${a[@]} ${b[@]} ${b[@]} | xargs -n1 | sort | uniq -u
# b差a
echo ${a[@]} ${a[@]} ${b[@]} | xargs -n1 | sort | uniq -u
# 交集的补集
echo ${a[@]} ${b[@]} | xargs -n1 | sort | uniq -u

闲话

这几天遇到了许多的烦心事,真的是及其让人不舒服。首先是一起租房子的人,人搬家了,一句话不说,之前我垫付的电费也没给我,这也就不说了,关键是问他的时候,它拒绝我发消息,把我屏蔽了。就冲他这做事的态度我想我也是必须把钱要回来的,还好现在钱已经还我了,有事得找管家,总得给他点压力这样人才老实啊。虽然一起租房子几个月了,我也是和他一句话没说过,果然人是时间久了才能看出好恶。所以在社会上不要没事打算用爱去温暖整个世界,就像贺函说的:“其实每个人只要管好自己的事,也就相安无事,天下太平了”

第二件事就是在淘宝买了个毛毯,一个星期没有发货,打算联系一下客服,可是联系好几次都是一个机器人,所以就退款了。可是呢,竟然被商家拒绝退款了,眼看东西都又寄回去了还是一个拒绝退款的状态,真的是担心,所以另外一个快递我就收了,然后退款流程也就撤销了,想着就算丢那也只丢一样吧,这个拿着好了。可是呢,物流竟然要我把货又给退回去,说是商家是这么留言的。来来回回折腾了好久,终于找到一个可以说话的客服,但是这个客服沟通起来也是有点难,总之就是心累。我也知道淘宝鱼龙混杂,我也没这个精力去分辨那些店家是好的,哪些是坏的。所以我还是用京东吧,京东还没怎么让我失望过。