Unix管道之美

2020-06-05 04:03:41

Unix理念强调构建简单和可扩展的软件。每个软件必须做一件事并且做好它。而且该软件应该能够通过一个公共界面--文本流--与其他程序协同工作。这是Unix的核心理念之一,它使ITSO功能强大、使用直观。

尽管UNIX系统引入了许多创新的程序和技术,但没有一个单一的程序或想法能让它很好地工作。相反,让SIT变得有效的是编程方法,一种使用计算机的哲学。虽然这一哲学不能用一句话写下来,但其核心是这样一种观点,即系统的力量更多地来自于程序之间的关系,而不是来自程序本身。许多UNIX程序孤立地做一些相当琐碎的事情,但与其他程序结合在一起,就会成为通用而有用的工具。

我想这很好地解释了这一点。此外,请观看BrianKernighan成为一名彻头彻尾的Chad,并解释UNIX OS的基本原理,在那里他还介绍了一个使用管道的示例。

不过,在这篇文章中,我想展示一些实践这一理念的例子--人们如何将不同的Unix工具结合在一起来完成一些强大的工作。

让我们从一个简单的列表开始-根据提交次数显示gitrepo的作者/贡献者列表,并按降序对列表进行排序(大多数提交位于顶部)。这是一项简单的任务,当你从管线的角度来考虑它的时候。Git日志用于显示提交日志。我们可以将--format=<;format>;选项传递给它,并说明我们希望以什么格式显示提交。--format=';%an';只打印每次提交的作者姓名。

$git日志--格式=';%an';|排序|uniq-c 4 Alice 1 Bob 1 Candice 3 Denise。

因此,uniq会打印出重复的行,但只打印彼此相邻的行。这就是我们必须首先传递输出进行排序的原因。c标志根据出现的次数为每行添加前缀。

您可以看到输出仍然按字母顺序排序。所以现在剩下的就是按数字排序了。在排序中有一个标志,-n标志。它根据数字的数值来考虑数字。

$git日志--格式=';%an';|SORT|uniq-c|SORT-nr 4 Alice 3 Denise 1 Candice 1 Bob。

还包括了-r标志,以便以相反的顺序打印列表。默认情况下,按升序对其进行排序。他们的“你有”--根据提交次数排序的作者列表。

您知道吗?您只需将“.json”附加到reddit url即可获得jsonresponse,而不是通常的html。这就提供了一个可能的世界!其中之一就是直接从命令行浏览表情包(并不完全是这样,因为实际的图像将显示在GUI程序上)。我们可以简单地将URL-https://reddit.com/r/memes.json。

$wget-O--Q';https://reddit.com/r/memes.json';';{";Kind";:";Listing";,";Data";:{";modhash";:";xyloiccqgm649f320569f4efb427cdcbd89e68aeceeda8fe1a";,";dist";:27,";子项";:[{";Kind";:";T3";,";数据";:{";Approved_at_UTC";:NULL,";subreddit";:";Memes";,";selftext";:";有关更多信息,请访问.';.更多行.。

我在这里使用wget是因为似乎Curl用户代理得到了不同的对待。显然,您可以通过简单地更改“User-Agent”头来绕过这个问题,但我只使用了wget。Wget有一个-O来提供输出文件名。大多数采用这种选项的程序也允许valueOf-它表示标准输出或输入,具体取决于上下文。-q选项只告诉wget保持安静,而不是打印诸如Progress sstatus之类的内容。现在我们可以使用一个大型的JSON结构。现在,要在命令行上有意义地解析和使用此JSON数据,我们可以使用JQ。JQ可以被认为是JSON的sed/尴尬。它有一种简单直观的语言,您可以参考FROMIT的手册页。

{";Kind";:";Listing";,";Data";:{";modhash";:";awe40m26lde06517c260e2071117e208f8c9b5b29e1da12bf7";,";dist";:27,";子项";:[],";之后";:";T3_gi892x";,";之前";:NULL}}。

所以这里我们有一些“Listing”类型的响应,我们可以看到我们有一个“Child”数组。该数组的每个元素都是一个帖子。

这是“Child”数组中的一个元素:

{";Kind";:";T3";,";Data";:{";subreddit";:";memes";,";selftext";:";";,";创建";:1589309289,";Author_Fullname";:";T2_4amma5w";,:0,";Title";:";,";subreddit_name_prefix";:";r/memes";,";down";:0,";Hide_Score";:false,";name";:";T3_gi8wkj";,";隔离&#。:FALSE,";permalink";:";/r/memes/comments/gi8wkj/its_hard_to_argue_with_his_assessment/";,";url";:";https://i.redd.it/6vi05eobdby41.jpg";,";upVote_Ratio";:0.9,";subreddit_type";:";PUBLIC";,";";https://b.thumbs.redditmedia.com/QZt8_SBJDdKLVnXK8P4Wr_02ALEhGoGFEeNhpsyIfvw.jpg";,";:11367,";TOTAL_ARMARDS_RECEIVED";:0,";分数";:11367,";作者_高级";:FALSE,";缩略图";:UPS";镀金";:{},";POST_HINT";:";image";,";.";";";";.";}}。

我已经减少了数据中键值对的数量。总共有105个项目。如您所见,您可以从帖子中获取许多有趣的数据属性。我们感兴趣的是帖子的url。这不是真正的reddit帖子的url,而是帖子内容的url。如果帖子的url是您想要的,那么它就是永久链接。因此,在本例中,url字段是meme图像的url。

我们可以使用以下命令简单地获取每个帖子的所有URL的列表:

忽略前两个链接,它们基本上是MODS发布的粘性帖子,它们的‘url’与‘permalink’是一样的。

JQ从标准输入读取,并提供给我们前面看到的JSON。.data.Children指的是我前面提到的帖子数组。而-.data.Children[]|.data.url的意思是“遍历数组中的每个元素,并打印每个元素的‘data’字段中的‘url’字段”。

所以我们得到了/r/memes“热门”帖子的所有URL列表。如果你想获得本周最热门的帖子,那么你可以点击https://reddit.com/r/memes/top.json?t=week.。史上最高职位?t=全部,年份?T=年份,依此类推。

一旦我们有了所有URL的列表,我们现在就可以将其通过管道传输到xarg.xargs是一个从标准输入构建命令行的非常有用的实用程序。下面是xarg的手册页所说的内容:

xargs从标准输入中读取由空格(可以用双引号或单引号或反斜杠来保护)或换行符分隔的项,并使用任何初始参数后跟从标准输入读取的项来执行命令(缺省值为/bin/echo)一次或多次。标准输入上的空行将被忽略

现在,我们只需将URL列表传递给图像查看器,比如接受URL作为有效参数的feh或eogh。

现在,feh弹出了表情包,我可以像在本地磁盘上一样,用箭头键浏览它们。

或者,我可以简单地使用wget下载所有图像,将feh替换为上面的wget。

可能性是无穷无尽的。此reddit JSON数据的另一个很好的用途是将桌面的墙纸设置为“热门”部分中/r/Earth porn的顶部向上的图像。

$wget-O--q reddit.com/r/Earth porn.json|jq';.data.Children[]|.data.url&-|head-1|xargs feh--bg-ill。

然后,如果您愿意,可以将其设置为每小时运行一次的cron-job。我在这里使用head命令只打印第一行,这将是顶部向上的帖子。就其本身而言,Head似乎做了一些非常琐碎和无用的事情,但在这种情况下,与其他程序一起工作,它就成了重要的一部分。

你看到Unix管道的威力了吗?从获取JSON数据,解析并从中获取相关数据,然后再次从URL获取图像,最后将其设置为墙纸,这一行完成了所有操作。

我用它做的另一件蠢事是每两个小时从/r/memes下载meme。这在我的机器上设置为cron作业。现在我的磁盘上大约有19566个表情包,占据了4.5G的空间。我为什么要那么做?别问我…

让我们用一个简单的例子来结束它。IMDb有一个功能,可以让你列出名单。您还可以查找其他用户创建的列表。例如,吹爆你的脑海中的电影。如果您向URL追加/导出,您将获得.csv格式的列表。

$cURL https://www.imdb.com/list/ls020046354/exportPosition,const,创建,修改,描述,标题类型,IMDB评级,运行时间(分钟),年份,流派,票数,发行日期,导演1,tt0137523,2017-07-30,2017-07-30,2017-07-30,搏击俱乐部,https://www.imdb.com/title/tt0137523/,电影,8.8,139,1999,戏剧,1780706,1999-09-10,David Fincher2,t0945513,2017-07-30,2017-07-30,2017-07-30,2017-07-30,2017-07-30,1780706,1999-09-10,david fincher2,t0945513,2017-07-30,2017-07-30,2017-07-30,2017-07-30电影,7.5,93,2011,#34;动作,戏剧,神秘,科幻,颤栗#34;,471234,2011-03-11,邓肯·琼斯3,tt0482571,2017-07-30,2017-07-30,The Prestige,https://www.imdb.com/title/tt0482571/,电影,8.5,130,2006,&34;戏剧,神秘,科幻,颤栗";,1133548,2006-10-17,克里斯托弗·诺兰4,t020.。神秘,颤栗&34;,1081848,2000-09-05,克里斯托弗·诺兰5,tt0144084,2018-01-16,2018-01-16,美国精神病,https://www.imdb.com/title/tt0144084/,电影,7.6,101,2000,&34;喜剧,犯罪,戏剧";,462984,2000-01-21,玛丽·哈龙6,t0364569,2018-01-16,2018-01-16,Oldeuboi,https://www.imdb.com/title/tt0364569/,,491476,2003-11-21,赞宇公园7,tt1130884,2018-10-08,禁闭岛,https://www.imdb.com/title/tt1130884/,电影,8.1,138,2010,&34;神秘,颤栗";,1075524,2010-02-13,马丁·斯科塞斯8,tt8772262,2019-12-27,2019年-12-27,米德索玛,https://www.imdb.com/title/tt8772262/,电影,7.1,148。

d选项用于指定每个字段的分隔符。田野之间用什么隔开?在本例中是逗号(,)。f选项是要打印的字段编号。在本例中,第六个字段是电影的标题。这还会打印CSV头“title”,因此要删除它,我们只需使用sed';1d';,意思就是从输入流中删除一行。

然后我们可以将电影列表通过管道传送到Shuf。Shuf只是随机地洗牌它的输入行,然后把它吐出来。

$curl https://www.imdb.com/list/ls020046354/export|Cut-d&39;,';-f 6|sed';1 d';|ShufAmerican Mental MidSomm源码Oldeuboi飞行俱乐部MementoShutter岛的威望。

现在只需通过管道将其输入head-1或sed';1q';,这将只打印第一行。每次运行此命令时,您都会得到一个随机选择。

$cURL https://www.imdb.com/list/ls020046354/export|CUT-d';,';-f 6|sed';1 d';|Shuf|Head-1源代码。

现在假设您还希望将URL与标题一起打印,无问题,剪切允许您使用--field=list指定要打印的多个字段

$cURL https://www.imdb.com/list/ls020046354/export|Cut-d&39;,';--FIELD=6,7|sed';1 d';|Shuf|Head-1Shutter Island,https://www.imdb.com/title/tt1130884/。

但是这有一个问题,如果电影标题中有逗号,那么你会得到一个完全不同的字段值。克服此问题的一种方法是使用如下所示的python一行程序:

$curl-s https://www.imdb.com/list/ls020046354/export|\python-c';导入csv,sys;[为csv.DictReader(sys.stdin)中的打印(a[";标题";],a[";url";])]';|\Shuf|Head-1Oldeuboi https://www.imdb.com/title/tt0364569/。

这些只是几个例子,你可以用管道在单行的外壳上完成很多事情。