您的位置:首页 > 运维架构 > Linux

Linux基础命令:文本处理工具之cut

2014-06-12 15:33 746 查看
大纲1、cut 介绍2、cut实例演示3、字符编码
文档版本
更新时间
备注
v1
2016-02-14
版本更新信息:
cut 版本
cut (GNU coreutils) 8.4

一、cut介绍

Cut out selected fields of each line of a file. Cut command can be used to display only specific columns from a text file or other command outputs. Cut 输入字符中指定的字段或指定的范围。若处理的是字段,则定界符隔开的即为各字段,而输出时字段也以给定的定界符隔开。默认的定界符为制表字符(TAB)。
我们可以通过man或者--help选项查看cut的使用帮助。
[root@localhost ~]# cut --help
Usage: cut [OPTION]... [FILE]...
Print selected parts of lines from each FILE to standard output.

Mandatory arguments to long options are mandatory for short options too.
-b, --bytes=LIST      select only these bytes
-c, --characters=LIST   select only these characters
-d, --delimiter=DELIM   use DELIM instead of TAB for field delimiter
-f, --fields=LIST     select only these fields;  also print any line
that contains no delimiter character, unless
the -s option is specified
-n             with -b: don't split multibyte characters
--complement    complement the set of selected bytes, characters
or fields.
-s, --only-delimited    do not print lines not containing delimiters
--output-delimiter=STRING  use STRING as the output delimiter
the default is to use the input delimiter
--help     display this help and exit
--version  output version information and exit

Use one, and only one of -b, -c or -f.  Each LIST is made up of one
range, or many ranges separated by commas.  Selected input is written
in the same order that it is read, and is written exactly once.
Each range is one of:

N     N'th byte, character or field, counted from 1
N-    from N'th byte, character or field, to end of line
N-M   from N'th to M'th (included) byte, character or field
-M    from first to M'th (included) byte, character or field
这里列出了我们最常使用的一些选项。下面详述几个重要选项:-b list The list following -b specifies byte positions (for instance, -b1-72 would pass the first 72 bytes of each line). When -b and -n are used together, list is adjusted so that no multi-byte character is split. If -b is used, the input line should contain 1023 bytes or less.
-c list The list following -c specifies character positions (for instance, -c1-72 would pass the first 72 characters of each line).
-f list The list following -f is a list of fields assumed to be separated in the file by a delimiter character (see -d ); for instance, -f1,7 copies the first and seventh field only. Lines with no field delimiters will be passed through intact (useful for table subheadings), unless -s is specified. If -f is used, the input line should contain 1023 characters or less.
list A comma-separated or blank-character-separated list of integer field numbers (in increasing order), with optional - to indicate ranges (for instance, 1,4,7; 1-3,8; -5,10(short for 1-5,10); or 3- (short for third through last field)).
-n Do not split characters. When -b list and -n are used together, list is adjusted so that no multi-byte character is split.
-d delim The character following -d is the field delimiter (-f option only).Default is TAB. Space or other characters with special meaning to the shell must be quoted. delim can be a multi-byte character.
-s Suppresses lines with no delimiter characters in case of -f option. do not print lines not containing delimiters. Unless specified, lines with no delimiters will be passed through untouched. file A path name of an input file. If no file operands are specified, or if a file operand is -, the standard input will be used.
说明:cut命令从文件的每一行剪切字节(bytes)、字符(characters)、字段(fields)并输出。cut以什么作为剪切的依据呢? 剪切依据:-b,按字节(bytes)切
-c,按字符(characters)切
-f, 按域(fields)切,通常结合 -d (delimiter)选项一起使用,默认TAB
范围表示:n 第n个字节/字符/字段

n- 从第n个字节/字符/字段到最后一个字节/字符/字段

n-m 从第n个字节/字符/字段到第m个字节/字符/字段,包括m

-m 从行的开头到第m个字节/字符/字段,包括m

二、cut实例演示

为了方便演示,我们创建一个测试文件myfile,内容如下:

[yy@localhost ~]$ cat myfile
cat command for file oriented operations.
cp command for copy files or directories.
ls command to list out files and directories with its attributes.

使用 -c 选项:按字符提取
a、如果我想要从myfile中提取每一行的第2个字符(character,-c option)

[yy@localhost ~]$ cut -c2 myfile
a
p
s
这里我们使用-c选项,然后接提取第几个字符。

b、提取一段范围(range)的字符(character, -c option),比如前3个字符和第5个字符
[yy@localhost ~]$ cut -c1-3,5 myfile
catc
cp o
ls o
这里需要注意的是:cut命令如果使用了-b,-c或-f选项,那么执行此命令时,cut会先把后面所有的范围进行【从小到大】排序,然后再提取。所以想通过指定范围的方式来排列特定的字符[字节/域]顺序是行不通的。
如,我想把第5个字符放在1-3个字符的前面, 我们把list的顺序调整, -c5,1-3:

[yy@localhost ~]$ cut -c5,1-3 myfile
catc
cp o
ls o
# 结果很明显,这样是不行滴。
## cut会先把-c后面所有的定位进行从小到大排序,然后再提取
[yy@localhost ~]$ cut -c1-3,5 myfile        # 实际上,cut会重新调整为1-3,5
c、如果我想提取第5个字符(character, -c option)之后的所有字符
[yy@localhost ~]$ cut -c5- myfile
command for file oriented operations.
ommand for copy files or directories.
ommand to list out files and directories with its attributes.
d、如果我想提取从行开始到第5个字符之间的所有字符(character, -c option)
[yy@localhost ~]$ cut -c-5 myfile
cat c
cp co
ls co

使用-f,-d选项:
我们知道 /etc/passwd 文件是以":"分隔的,那么我们就用它来演示,为了方便显示,只显示3行。

e、我们想从/etc/passwd中仅提取出用户名

[yy@localhost ~]$ head -n3 /etc/passwd | cut -d: -f1
root
bin
daemon
我们使用-d选项来指定域分隔符(delimiter),【默认的分隔符为TAB】。然后我们用-f选项指定选择哪一个域。
f、如果我想提取shell为/bin/bash的用户的用户名和家目录字段
[yy@localhost ~]$ grep 'bash' /etc/passwd | cut -d: -f1,6
root:/root
yy:/home/yy
g、同上,只是我们想提取1-4以及6,7域
[yy@localhost ~]$ grep 'bash' /etc/passwd | cut -d: -f1-4,6,7
root:x:0:0:/root:/bin/bash
yy:x:500:500:/home/yy:/bin/bash
h、提取所有的域,并排除特定的域
[yy@localhost ~]$ head -n3 /etc/passwd | cut -d':' --complement -f7
root:x:0:0:root:/root
bin:x:1:1:bin:/bin
daemon:x:2:2:daemon:/sbin
提取了除第7个域之外的所有域。

使用-s选项:
不打印那些没有包含指定分隔符的行,do not print lines not containing delimiters
i、如果我们指定一个不是":"的分隔符,那么cut仅仅打印整个行

[yy@localhost ~]$ head -n3 /etc/passwd | cut -d'|' -f1
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
如果我只想过滤和打印出包含指定分隔符的行,怎么办? 使用 -s 选项
[yy@localhost ~]$ head -n3 /etc/passwd | cut -s -d'|' -f1
[yy@localhost ~]$
因为3行都没有包含"|"分隔符, 所以都没有被打印。

使用--output-delimiter 改变默认的输出分隔符
j、提取/etc/passwd中的第1,6,7域,以"#"进行分隔
[yy@localhost ~]$ head -n3 /etc/passwd | cut -d':' -f1,6,7 --output-delimiter='#'
root#/root#/bin/bash
bin#/bin#/sbin/nologin
daemon#/sbin#/sbin/nologin
k、指定输出分隔符为换行符(\n)
这里比较特殊,我们必须使用 $'\n'来指示使用换行符
指定为'\n', --output-delimiter='\n'

[yy@localhost ~]$ head -n2 /etc/passwd | cut -d':' -f1,6,7 --output-delimiter='\n'
root\n/root\n/bin/bash
bin\n/bin\n/sbin/nologin
指定为 $'\n', --output-delimiter=$'\n'

[yy@localhost ~]$ head -n2 /etc/passwd | cut -d':' -f1,6,7 --output-delimiter=$'\n'
root
/root
/bin/bash
bin
/bin
/sbin/nologin

关于字符(-c)和字节(-b)的讨论
POSIX系统中,cut识别多字节字符(multibyte characters)。因此,“字符(character)” 与 “字节(byte)”意义不同。
对于使用ASCII编码的文本来说, -c和-b并没有太大的区别,但是对于多字节的情况,它们就大大的不同了。我们准备示例文件 test_cn.txt,内容如下:
[yy@localhost ~]$ cat test_cn.txt
复旦大学
上海交通大学
南京大学
中国人民大学
香港科技大学
我们提取第2个字符出来
[yy@localhost ~]$ cut -c2 test_cn.txt
旦
海
京
国
港
那么,我们使用-b选项呢?
[yy@localhost ~]$ cut -b2 test_cn.txt
看到了吧,上面发生了什么情况,全部都乱码显示

。用-c则会以字符为单位,输出正常;而-b只会傻傻的以字节(8位二进制位)来计算,输出就是乱码。既然提到了这个知识点,就再补充一点。

三、什么是编码(对应的编码表)

在计算机中,所有的数据在存储和运算时都要使用二进制数表示(因为计算机用高电平和低电平分别表示1和0),例如,像a、b、c、d这样的52个字母(包括大写)、以及0、1等数字还有一些常用的符号(例如*、#、@等)在计算机中存储时也要使用二进制数来表示,而具体用哪些二进制数字表示哪个符号,当然每个人都可以约定自己的一套规则(这就叫编码),而大家如果要想互相通信而不造成混乱,那么大家就必须使用相同的编码规则,于是美国有关的标准化组织就出台了所谓的ASCII编码,统一规定了上述常用符号用哪些二进制数来表示。
ASCII 码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符。标准ASCII 码也叫基础ASCII码,使用7 位二进制数来表示所有的大写和小写字母,数字0 到9、标点符号, 以及在美式英语中使用的特殊控制字符。所以,对于英文来说一个字符对应一个字节是没有任何问题的,一个字符8bit。但是问题是汉字编码数量庞大,字形复杂,所以只用第一个字节是没有办法表示的。 所以必须用多个字节来表示一个字符。常见的中文字符集有: GB2312-80字符集,中文名国家标准字符集, Big-5字符集,中文名大五码, GBK字符集,中文名国家标准扩展字符集。ISO/IEC 10646 / Unicode字符集,一个字符用16bit表示。

字符在计算机中的存储:

在 ASCII 阶段,单字节字符串使用一个字节存放一个字符(SBCS)。比如,"Bob123" 在内存中为:
426F6231323300
Bob123\0
在使用 ANSI 编码支持多种语言阶段,每个字符使用一个字节或多个字节来表示(MBCS),因此,这种方式存放的字符也被称作多字节字符。比如,"中文123" 在中文 Windows 95 内存中为7个字节,每个汉字占2个字节,每个英文和数字字符占1个字节。
D6 D0
CE C43132330
123\0
在 UNICODE 被采用之后,计算机存放字符串时,改为存放每个字符在 UNICODE 字符集中的序号。目前计算机一般使用 2 个字节(16 位)来存放一个序号(DBCS),因此,这种方式存放的字符也被称作宽字节字符。比如,字符串 "中文123" 在 Windows 2000 下,内存中实际存放的是 5 个序号:
2D 4E87 6531 0032 0033 0000 00
123\0
当遇到多字节字符时,可以使用-n选项,-n用于告诉cut不要将多字节字符拆开。
[yy@localhost ~]$ cut -b2 test_cn.txt
上面为乱码显示。
使用-n选项
[yy@localhost ~]$ cut -b2 -n test_cn.txt
什么也没有打印。它就不会去拆多字节字符了。

四、cut的不足

猜出来了吧?对,【就是在处理连续多分隔符时。】

如果文件里面的某些域是由若干个空格或其他分隔符来间隔的,那么用cut就有点麻烦了,因为cut只擅长处理“以一个字符间隔”的文本内容。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Linux 字符编码 cut