SHELL 命令行技巧

摘抄:http://blog.jobbole.com/114238/

我们会谈及的内容

  • ICONV
  • HEAD
  • TR
  • WC
  • SPLIT
  • SORT & UNIQ
  • CUT
  • PASTE
  • JOIN
  • GREP
  • SED
  • AWK

ICONV

文件编码总是棘手的问题。目前大部分文件都是采用的 UTF-8 编码。要想了解 UTF-8 的魔力,可以看看这个优秀的视频。尽管如此,有时候我们还是会收到非 UTF-8 编码的文件。这种情况下就需要尝试转码。iconv 就是这种状况下的救世主。iconv 是一个简单的程序,可以输入某种编码的文本,然后以另一种编码输出。

# Converting -f (from) latin1 (ISO-8859-1)
# -t (to) standard UTF_8
iconv -f ISO-8859-1 -t UTF-8 <  input.txt  > output.txt

  • 常用选项:
    • iconv -l 列出所有支持的编码
    • iconv -c 不作提示就丢弃无法转换的字符

HEAD

如果你是重度Pandas的用户,那么你会对head很熟悉。通常在处理新数据时,我们想要做的第一件事就是了解究竟存在那些东西。这会引起Panda启动,读取数据,然后调用df.head() – 很费劲,至少可以说。head,不需要任何标志,将输出文件的前10行。head真正的能力在于彻查清除操作。 例如,如果我们想将文件的分隔符从逗号改变为pipe通配符。一个快速测试将是:head mydata.csv | sed ‘s/,/|/g’

# Prints out first 10 lines
head filename.csv
# Print first 3 lines
head -n 3 filename.csv
  • 有用的选项:
    • head -n 输出指定行
    • head -c 输出指定的字节

TR命令

Tr类似于翻译,它是基于文件清理的一个强大使用的工具。一个理想的用法是替换文件中的分隔符。

#将文件中的制表符分割转换成逗号
cat tab_delimited.txt | tr "\t" "," comma_delimited.csv

Tr的另一个特性是在你的处理中设置上所有的[:class:]变量。包括:

[:alnum:] 所有字母和数字
[:alpha:] 所有字母
[:blank:] 所有水平空白
[:cntrl:] 所有控制字符
[:digit:] 所有数字
[:graph:] 所有可打印的字符,不包括空格
[:lower:] 全部小写字母
[:print:] 所有可打印的字符,包括空格
[:punct:] 所有标点符号
[:space:] 所有的水平或垂直空格
[:upper:] 全部大写字母
[:xdigit:] 所有十六进制数字

可以将这些多样化的变量链接在一起,组成一个强大的程序。下面是一个基于字数统计的程序,用来检查你的README文件是否使用过度。

cat README.md | tr "[:punct:][:space:]" "\n" | tr "[:upper:]" "[:lower:]" | grep . | sort | uniq -c | sort -nr

另外一个例子用于正则表达式

# 将所有的大写字母转换成小写
cat filename.csv | tr '[A-Z]' '[a-z]'
  • 有用的选项:
    • tr -d删除字符
    • tr -s压缩字符
    • \b退格
    • \f换页
    • \v垂直选项卡
    • \NNN八进制值为NNN的字符

WC

字数统计。它的价值主要体现在使用 -l 参数可以进行行数统计。

# Will return number of lines in CSV
wc -l gigantic_comma.csv

个用这个工具来验证各个命令的输出实在方便。因此,如果我们要在文件中转换分隔符,然后运行 wc -l,验证总行数是相同的。如果不同,我们就知道一定是哪里出错了。

  • 常用选项:
    • wc -c 打印字节数
    • wc -m 打印字符数
    • wc -L 打印最长一行的长度
    • wc -w 打印字数

SPLIT命令

文件大小可以有显著变化。根据工作的不同,拆分文件是有益的,就像split。基本用法如下:

#我们拆分这个CSV文件,每500行分割为一个新的文件new_filename
split -l 500 filename.csv new_filename_

# filename.csv
# ls output
# new_filename_aaa
# new_filename_aab
# new_filename_aac

两个地方很奇怪:一个是命名方式,一个是缺少扩展名。后缀约定可以通过-d标识来数字化。添加文件扩展名,你需要执行下面这个find命令。他会给当前文件夹下的所有文件追加.csv后缀,所以需要小心使用。

find . -type f -exec mv '{}' '{}'.csv \;

# ls output
# filename.csv.csv
# new_filename_aaa.csv
# new_filename_aab.csv
# new_filename_aac.csv
  • 有效的选项:
    • split -b按特定字节大小拆分
    • split -a生成长度为N的后缀
    • split -x使用十六进制后缀分割

SORT & UNIQ

前面的命令是显而易见的:他们按照自己说的做。这两者提供了最重要的一击(即去重单词计数)。这是由于有uniq,它只处理重复的相邻行。因此在管道输出之前进行排序。一个有趣的事情是,sort -u将获得与sort file.txt | uniq相同的结果。

Sort确实对数据科学家来说是一种很有用的小技巧:能够根据特定的列对整个CSV进行排序。

# Sorting a CSV file by the second column alphabetically
sort -t"," -k2,2 filename.csv
# Numerically
sort -t"," -k2n,2 filename.csv
# Reverse order
sort -t"," -k2nr,2 filename.csv

这里的-t选项是指定逗号作为分隔符。通常假设是空格或制表符。此外,-k标志是用来指定我们的键的。它的语法是-km,n,m是起始字段,n是最后一个字段。

  • 有用的选项:
    • sort -f 忽略大小写
    • sort -r 逆序
    • sort -R 乱序
    • uniq -c 计算出现次数
    • uniq -d 只打印重复行

CUT命令

cut用于删除列。举个栗子,如果我们只想要第一列和第三列。

cut -d, -f 1,3 filename.csv

选择除了第一列以外的所有列

cut -d, -f 2- filename.csv

与其他的命令组合使用,cut命令作为过滤器

#打印存在“some_string_value”的第1列和第3列的前10行

head filename.csv | grep "some_string_value" | cut -d, -f 1,3

找出第二列中唯一值的数量。

cat filename.csv | cut -d, -f 2 | sort | uniq | wc -l

# 计算唯一值出现的次数,限制输出前10个结果

cat filename.csv | cut -d, -f 2 | sort | uniq -c | head

PASTE

paste 是个有趣的小命令。如果你想合并两个文件,而这两个文件的内容又正好是有序的,那 paste 就可以这样做。

# names.txt

adam

john

zach

# jobs.txt

lawyer

youtuber

developer
# Join the two into a CSV

paste -d ',' names.txt jobs.txt > person_data.txt
# Output

adam,lawyer

john,youtuber

zach,developer

关于更多 SQL_-esque 变体,请看下面。


JOIN

Join是一种简单的、准切向的SQL。最大的区别在于Join将返回所有列,匹配可能只发生在一个字段上。默认情况下,join将尝试使用第一列作为匹配键。对于不同的结果,需要以下语法:

# Join the first file (-1) by the second column

# and the second file (-2) by the first

join -t"," -1 2 -2 1 first_file.txt second_file.txt

标准连接是一个内部连接。然而,外部连接也可以通过-af滞后来实现。另一个值得注意的是-e标志,如果发现有字段丢失,它可以用来替换成其他值。

# Outer join, replace blanks with NULL in columns 1 and 2

# -o which fields to substitute - 0 is key, 1.1 is first column, etc...

join -t"," -1 2 -a 1 -a2 -e ' NULL' -o '0,1.1,2.2' first_file.txt second_file.txt

虽然它不是最容易使用的命令,但是在绝望的时刻,它就是唯一可用的措施。

  • 常用的选项:
    • join -a 打印未成对的行
    • join -e 替换缺失字段
    • join -j 等同于 -1 FIELD -2 FIELD

GREP

全局搜索正则表达式并输出,或使用grep;可能是最知名的命令,并且有很好的理由。 Grep具有很强的能力,特别是在大型代码库中查找方法。在数据科学领域,它充当了其他命令的改进机制。但其标准用法也很有用。

# 递归搜索并列出当前目录下包含'word'的所有文件

grep -lr 'word' .

# 列出包含word的文件数目

grep -lr 'word' . | wc -l

对包含word/pattern的行数进行计数

grep -c 'some_value' filename.csv

# 同样的功能,但是按照文件名列出当前目录下所有包含该关键词的文件

grep -c 'some_value' *

Grep使用or运算符- \|来检索多个值.

grep "first_value\|second_value" filename.csv
  • 有用的选项
    • alias grep=”grep –color=auto” 使grep支持彩色输出
    • grep -E 使用扩展正则表达式
    • grep -w 仅匹配完整单词
    • grep -l 打印匹配文件的名称
    • grep -v 倒序匹配

大杀器

Sed和Awk是本文两个最有用的命令。为了简洁,我不会讨论那些令人费解的细节。相反,我会讨论各种各样的命令来证明他们令人印象深刻的实力。如果你想了解的更多,这本书就可以。

SED

在内核中sed是一个流编辑器。它擅长替换,但是也可以用来重构。
最基本的sed命令包含了s/old/new/g。也就是全局搜索旧值,替换新值。没有/g 我们的命令可能在第一次出现旧值就会终止。
为了尽快了解它的能力,我们来看一个例子。在这个情况你会拿到下面的文件:

balance,name
$1,000,john
$2,000,jack

我们要做的第一件事就是移除美元符。-i 标识表示就地修改。" 就是代表一个零长度文件扩展,因此重写我们的初始文件。理想情况下,你会单独测试这些并输出到一个新文件。

sed -i '' 's/\$//g' data.txt

# balance,name
# 1,000,john
# 2,000,jack

下一步,我们的balance列的逗号。

sed -i '' 's/\([0-9]\),\([0-9]\)/\1\2/g' data.txt

# balance,name
# 1000,john
# 2000,jack

最终,Jack有一天起来并准备辞职了。所以,再见吧,我的朋友。

sed -i '' '/jack/d' data.txt

# balance,name

# 1000,john

就像你所看到的,sed功能强大,但是乐趣不止于此。

AWK

最好的放最后。Awk不仅是一个简单的命令:它是一个成熟的语言。在本文中包含的每一个命令中,awk目前是最酷的。如果你发现它令你印象深刻,这有大量的资源- 看,和
awk包含的常用案例:

  • 文本处理
  • 格式化文本报告
  • 执行计算操作
  • 执行字符串操作

Awk在其最初雏形可以与grep平行。

awk '/word/' filename.csv

或者多使用一点魔法,让grep和cut结合。在这,awk对所有行通过word打印了以tab分隔的第三和第四列。-F,只是将分隔符变为逗号。

awk -F, '/word/ { print $3 "\t" $4 }' filename.csv

Awk具有大量有用的内置变量。例如, NF -字段数 – 和NR – 记录数。为了获取文件中这53个记录:

awk -F, 'NR == 53' filename.csv

添加一个小窍门可以基于一个值或者多个值过滤。下面的第一个例子,会打印这些记录中第一列为string的行数和列。

awk -F, ' $1 == "string" { print NR, $0 } ' filename.csv

# Filter based off of numerical value in second column

awk -F, ' $2 == 1000 { print NR, $0 } ' filename.csv

多数值表达式:

# Print line number and columns where column three greater
# than 2005 and column five less than one thousand

awk -F, ' $3 >= 2005 && $5 <= 1000 { print NR, $0 } '  filename.csv

计算第三列之和:

awk -F, '{ x+=$3 } END { print x }' filename.csv

计算那些第一列值为“something”的第三列之和。

awk -F, '$1 == "something" { x+=$3 } END { print x }' filename.csv

获取文件的行数列数:

awk -F, 'END { print NF, NR }' filename.csv

# Prettier version

awk -F, 'BEGIN { print "COLUMNS", "ROWS" }; END { print NF, NR }' filename.csv

打印出现过两次的行:

awk -F, '++seen[$0] == 2' filename.csv

移除多行:

# Consecutive lines

awk 'a !~ $0; {a=$0}']

# Nonconsecutive lines

awk '! a[$0]++' filename.csv

# More efficient

awk '!($0 in a) {a[$0];print}

使用内置函数gsub()替换多个值。

awk '{gsub(/scarlet|ruby|puce/, "red"); print}'

这个awk命令合并了多个CSV文件,忽略头并在结尾追加。

awk 'FNR==1 && NR!=1{next;}{print}' *.csv > final_file.csv

需要精简一个大文件?好的,awk可以在sed的帮助下完成这件事。具体来说,基于一个行数,这个命令将一个大文件分为多个小文件。这个一行文件也会添加一个扩展名。

sed '1d;$d' filename.csv | awk 'NR%NUMBER_OF_LINES==1{x="filename-"++i".csv";}{print > x}'

# Example: splitting big_data.csv into data_(n).csv every 100,000 lines

sed '1d;$d' big_data.csv | awk 'NR%100000==1{x="data_"++i".csv";}{print > x}'
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容