绑定完请刷新页面
取消
刷新

分享好友

×
取消 复制
讲真,你真的会用 Unix 命令吗?
2019-06-18 17:40:50

点击▲关注 “CU技术社区”   给公众号标星置顶

更多精彩 时间直达


关于那些常用的 Unix 命令,你不知道的功能!

作者 | Vegard Stikbakke 

译者 | 弯月  责编 | 屠敏

以下为译文:

我逐渐意识到,Unix 的命令行工具可以解决一切与文字处理有关的问题。我来讲一个我遇到过的问题,以及怎样用 Unix 命令行工具解决的。

问题

我在做我的硕士论文研究。像许多统计学家一样,我需要进行许多模拟。首先我利用一些数字的种子(以保证可复现性)来模拟了一些数据,然后在这些数据上用一个算法来估算一些东西。每次运行模拟时我都会创建一些文件,大概像下面这样:

dataset-directory/0001_data.csv
dataset-directory/0001_A.csv

但有时候运行会失败。这并不是太严重,模拟失败了我只需要运行另一个模拟就好了。比如,0001 这个数据我成功地运行了算法 A。因此我想在 0001 数据上使用算法 B。但我真正需要的是跟踪哪些命令失败了。

在许多数据上运行算法 A 之后,我得到了一大堆文件,像这样:

dataset-directory/0001_data.csv
dataset-directory/0001_A.csv
dataset-directory/0002_data.csv
dataset-directory/0002_A.csv
dataset-directory/0003_data.csv
dataset-directory/0003_A.csv
dataset-directory/0004_data.csv
dataset-directory/0005_data.csv
dataset-directory/0005_A.csv
dataset-directory/0006_data.csv
dataset-directory/0006_A.csv
dataset-directory/0007_data.csv
dataset-directory/0007_A.csv
dataset-directory/0008_data.csv
dataset-directory/0009_data.csv
dataset-directory/0009_A.csv
...
dataset-directory/0499_A.csv

通过观察得知算法 A 在数据 0004 和 0008 上的结果不存在。那么,怎样才能列出所有 A 没有成功的数据呢?

我当然可以手工来做,但那样很容易出错,而且很麻烦。要是能写程序完成就好了!

解决方案

简单地来说,那些没有成功的就是从0001到0500的数字中去掉那些成功了的数字。而得到数字列表的好命令就是 seq:

$> seq 10
1
2
3
4
5
6
7
8
9
10

(如果只给出一个数字,那么默认序列从1开始。当然,seq 2 10也会按照你期待的那样工作。)

现在,如果我能获得成功运行的列表,就可以通过 seq 命令生成所有可能的数字,再交叉检查两个列表来获得想要的结果了!

许多命令行工具只完成一项工作。例如,cut 可以获得每行指定位置上的字符:

$> cat text
Lorem ipsum
dolor sit amet
$> cat text | cut -c 2-5
orem
olor

注意这里使用了所谓的“管道运算符” | 。我说过,许多工具只做一件事,而且把那件事做到好。很方便的是这些工具可以组合使用。使用管道,左边命令的结果就会变成右边命令的输入。注意这些命令会将输入当做一系列行来处理,通常来说这非常方便。

我们可以把成功的文件名单列表利用管道输入至 grep 命令,该命令可以使用正则表达式来查找。由于所有文件都以同样长度的四个数字开始,我们可以利用正则表达式 \d\d\d\d 来匹配这四个连续的数字,然后将文件末尾的 A 算法加到正则表达式中。要获得文件列表,每行一个文件,只需执行 ls。(尽管直接调用 ls 时并不会显示成每行一个文件,但放在管道中时输出就会变成这样。)

$> ls dataset-directory | grep '\d\d\d\d_A.csv'
0009_A.csv
0001_A.csv
0002_A.csv
0005_A.csv
0007_A.csv
0003_A.csv
0006_A.csv
...

出于某些原因,在使用 grep 之后这里的顺序混乱了。我们可以使用 sort 命令来改正。而且由于我们只关心数字,可以使用 cut -c 1-4 来取出数字部分。

$> ls dataset-directory | grep '\d\d\d\d_A.csv' | sort | cut -c 1-4
0001
0002
0003
0005
0006
0007
0009
...
0499

这些数字跟 seq 命令的结果不太一样,因为它们前面补了零。我们可以使用一段 Python 脚本将它们转成整数。

# parse.py
import sys

for line in sys.stdin:
    i = int(line)
    print(i)

现在将结果用管道导入这个脚本就能得到我们需要的数字:

$> ls dataset-directory | grep '\d\d\d\d_A.csv' | cut -c 1-4 | python3 parse.py
1
2
3
5
6
7
9
...
499

接近目标了!现在需要找出怎样才能交叉检查这两个数字的列表。幸运的是,有个命令叫做comm,它能检查两个输入流中的公共字符。为了将上面这个命令的输出作为输入使用,我们可以将其求值后重定向,只需使用<(...)即可实现:

$> comm <(ls dataset-directory | grep '\d\d\d\d_A.csv' | cut -c 1-4 | python3 parse.py) <(seq 500)
        1
        2
        3
    4
        5
        6
        7
    8
        9
    10
...
    500

这个输出不是太好理解。阅读 comm 的手册(运行 man comm)可以发现,comm 会“产生三列的输出,分别是:只存在于 file1 的行,只存在于 file2 的行,以及存在于两个文件的行”。要去掉列(其实它是空的,因为没有任何数字只存在于文件列表中),可以在调用 comm 时加入参数-1。我们也不关心同时存在于两个输入中的数字,因此还要传递标志-3。

$> comm -1 -3 <(ls dataset-directory | grep '\d\d\d\d_A.csv' | cut -c 1-4 | python3 parse.py) <(seq 500)
4
8
...
500

搞定!

网友说



这个方法发布之后,在 Hacker News(https://news.ycombinator.com/item?id=19160659)上引发无数网友参与讨论:

评论 1:

Unix CLI 工具有意思的地方在于有数百万种有效的方法来解决问题。我还想到了我自己的“更好”的解决方案,跟这里说过的大多数方法完全不同的方法。但这不是重点。

这篇文章的优点在于它遵循逐步解决问题的过程。我发现很多与我一起工作的程序员都在努力解决 CLI 问题,我觉得这有点令人惊讶。但我认为这完全取决于你如何看待这样的问题。

如果你从“我如何构建一个函数来操作这个原始数据?”或“哪种数据结构能表达这些文件名之间的关系?”那么肯定会遇到困难。但是,如果你考虑“如何改变这些数据以消除无关的细节?”和“我有什么工具可以解决数据上的问题,如果有一些麻烦,我怎么能解决这些麻烦?”并且如果能接受采用逐步的方式,而不是构建和操纵整个抽象逻辑结构,那么你就可以有效地利用这些工具在几分钟之内解决这些问题,无需花费几小时。

评论 2:

这篇文章的问题是:“cut”命令后的参数并没有什么标准格式。

更糟糕的是,看似有标准格式,其实被许多其他格式破坏了。通常,这些格式取决于初的作者,以及当时人们流行的想法。所以,有时候标志会“聚集”在一起,同时假设多字符的标志会使用两个横线作为开始。后来一些程序开始用一个横线来表示多字符的标志。还有许多其他的不一致。如果我学习了cut的基本范围语法,我能知道 imagemagick 的基本语法吗?

这些不一致在技术上并不冲突,因为每个只存在于特定的背景下。但是,如果看到那些不一致的东西被放在管道两侧,特别是当其中一个是非标准用法时,理智上真的很痛苦。(或者,即使它只是你需要的一个命令,但是你使用了错误的标志语法。)这一切都增加了认知负荷。

哦,从 Bash 转到 Python 语言是一个巨大的风险。如果你每天使用 Python 编写脚本,那可能还问题不大。但对于读者来说,语言边界是巨大的。因为用户不仅需要处理运行时错误和格式错误,而且还需要处理语言错误。如果命令行跳出一个语法错误或异常,我相信大多数读者就不会再读下去了。

原文:http://vegardstikbakke.com/unix/

本文转自 CSDN,如需转载,请注明来源出处。

分享好友

分享这个小栈给你的朋友们,一起进步吧。

专业的官方救援小分队
创建时间:2019-11-07 09:33:49
我是一个官方吐槽小栈我们是技术栈的搬砖IT民工。 我知道你们在使用小栈的过程中会遇到很多问题: 迭代功能太鸡肋? 界面太low? 编辑器难用到爆? ··· 需求尽管提,槽点尽管说,技术救援小分队在线为您灭火,致力于提供专业的解答,提供迅疾的反馈。 悄悄的说,毛线不懂的运营喵、产品狗他们不在,我们一起吐槽!
展开
订阅须知

• 所有用户可根据关注领域订阅专区或所有专区

• 付费订阅:虚拟交易,一经交易不退款;若特殊情况,可3日内客服咨询

• 专区发布评论属默认订阅所评论专区(除付费小栈外)

栈主、嘉宾

查看更多
  • 山中老狐狸
    栈主
  • 栈栈
    嘉宾
  • gaokeke123
    嘉宾
  • Ys
    嘉宾

小栈成员

查看更多
  • gyu
  • aabbcc1832611
  • 飘絮絮絮丶
  • h313895741
戳我,来吐槽~