刷题中熟悉Shell命令之Tenth Line和Transpose File [leetcode]

首先介绍题目中要用的4个Shell命令 sed awk head tail的常用方法。(打好地基,才能建成高楼!)

sed:(转自:http://www.cnblogs.com/barrychiao/archive/2012/09/27/2706300.html)

1.定位行

sed命令用来处理文本,在处理前首先要找得到待处理的行,这是逻辑上必须的。所以需要首先定位,然后对定位到的各行进行各种处理,包括插入,删除,替换等。
sed -n '10p' testfile // sed命令默认会打印出经过处理后所有的文本,-n选项则不打印这种默认文本。10为要定位的行,找到之后执行p命令,打印这一行。
sed -n '1,10p' testfile // 打印1-10行。
sed -n '2,$p' testfile // 打印第二行到最后一行。
sed -n '3~2p' testfile // 打印第3,5,7,9,…….行,你懂得。
sed -n '/Barry/,10p' testfile // 首先找到第一个匹配/Barry/(可以是其他基本正则表达式)的行,打印从这一行到第10行。
sed -n '1,3!p' testfile // 打印1-3行以外的行("!"的作用)。
sed -n '1{n;p}' testfile // 首先定位到第一行,然后执行命令n,定位到第一行的下一行,然后执行p打印,可见定位之后可以用 {}执行命令组合。
sed -n 'p' testfile // 什么都不写,则定位全部的行。
采用a,b这种模式定位时,首先定位a(如果超出范围或者未找到,就不会去查找b),然后定位b,如果b这一行在a的上面会出现什么状况呢?例如:
sed -n '/Barry/,/Hello/p' testfile 
该首先会定位到/Barry/,如果/Hello/这一行在/Barry/这一行上面,则只打印/Barry/这一行。为什么会这样?原来,sed定位是不回退的,即找到了/Barry/这一行之后,就从这一行下面找/Hello/,当然找不到了,所以只打印了/Barry/这一行。

2.命令

在定位之后当然是执行指定的命令了:d命令是删除命令。a命令在行后插入一行。i命令在行前插入一行。c命令替换行,当替换目标是连续的行时,把整体替换成一行。-r 选项使sed支持扩展正则表达式。s命令是替换命令,通常格式是line1,line2s/字符串1/字符串2/g,即把line1~line2的字符串1全部用字符串2代替,字符串1可以是正则表达式。这里不再对正则表达式详细介绍。如果末尾不加g字符,则表示只替换每行的第一个匹配的字符串。$是正则表达式的行尾标志。y命令替换以字符为单位,而s命令以字符串为单位。

看实例:
sed '1,3d' testfile // 删除1-3行,打印剩余的文本,注意,此时文件本身并没有改变。
sed -n '5,10a helloworld' testfile // 在5-10行每一行后面都增加一行 helloworld。
sed -n '5,10i helloworld' testfile // 在5-10行每一行前面都增加一行 helloworld。
sed -n ‘5~3c helloworld’ testfile //把5,8,11,14,17,20,23,26……依次替换为helloworld。
sed -n '5,10c helloworld' testfile //  把5-10行整体替换成一行helloworld。
sed -n -r '5,10s/yes|Yes/no/gp' testfile // 5-10行的yes或者Yes被替换成no。 

sed '1,10s/$/helloworld/' testfile // 在1~10行中,替换每行的行尾设置为helloworld。
sed '5,10y/abc/ABC/' testfile // 5-10行的a被换成A,b被换成B,c被换成C,类似tr命令的功能。
sed '/My/r textfile' testfile // r命令是读命令,sed使用该命令将一个文本文件中的内容加到当前行的下面。
sed -n '1,10w newfile' testfile // 将1-10行写入newfile。w命令可以将指定的行写入指定的文件。
sed -n '/root/{=;p}' testfile // 定位到/root/行之后,打印行号,然后打印这一行。"="是打印行号的命令。

 3.特殊选项 

-i选项表示对真实文件进行操作,所做的更改将保存到文件中。-s,则将多个文件读入,当作一个整体处理,-s选项使分别处理。e选项可以进行多次处理。每次匹配到的行执行多个命令。命令之间用";"分隔。

sed -i '1,10d' testfile // 直接在文件中删除1~10行。
sed -s '1d' testfile1 testfile2 testfile3 // 此处有三个文件,如果不加-s,则将三个文件读入,当作一个整体处理,-s选项使分别处理。
sed -e '/root/p' -e '/Barry/d' testfile // 此处用-e选项可以进行多次处理,第一次打印/root/行,第二次删除/Barry/行。
sed -e '/root/{n;p}' -e '/Barry/{n;d}' testfile // 每次处理时,可以对每次匹配到的行执行多个命令。命令之间用";"分隔。

awk

命令行格式:

awk [-F  field-separator]  'commands'  input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。 input-file(s) 是待处理的文件。
在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。
用$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推

'commands'的格式
awk '{pattern + action}' {filenames}   '{pattern + action}'可以被总结为模式和操作

模式pattern :
  转自: http://man.linuxde.net/awk
  • /正则表达式/:使用通配符的扩展集。
  • 关系表达式:使用运算符进行操作,可以是字符串或数字的比较测试。
  • 模式匹配表达式:用运算符~(匹配)和~!(不匹配)。
  • BEGIN语句块、pattern语句块、END语句块。

  操作action:

    操作由一个或多个命令、函数、表达式组成,之间由换行符或分号隔开,并位于大括号内{}。

    主要部分是:

  • 变量或数组赋值
  • 输出命令
  • 内置函数
  • 控制流语句

  awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file

  一个awk脚本通常由:BEGIN语句块、能够使用模式匹配的通用语句块、END语句块3部分组成,这三个部分是可选的。任意一个部分都可以不出现在脚本中,脚本通常是被单引号或双引号中,

  例如: awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename

  awk "BEGIN{ i=0 } { i++ } END{ print i }" filename


  第一步:执行BEGIN{ commands }语句块中的语句;

  第二步:从文件或标准输入(stdin)读取一行,然后执行pattern{ commands }语句块,它逐行扫描文件,从第一行到最后一行重复这个过程,直到文件全部被读取完毕。

  第三步:当读至输入流末尾时,执行END{ commands }语句块。

  BEGIN语句块在awk开始从输入流中读取行之前被执行,这是一个可选的语句块,比如变量初始化、打印输出表格的表头等语句通常可以写在BEGIN语句块中。

  END语句块在awk从输入流中读取完所有的行之后即被执行,比如打印所有行的分析结果这类信息汇总都是在END语句块中完成,它也是一个可选语句块。

  pattern语句块中的通用命令是最重要的部分,它也是可选的。如果没有提供pattern语句块,则默认执行{ print },即打印每一个读取到的行,awk读取的每一行都会执行该语句块。

awk的内置变量
ARGC               命令行参数个数
ARGV               命令行参数排列
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                浏览文件的记录数
FS                 设置输入域分隔符,等价于命令行 -F选项
NF                 浏览记录的域的个数
NR                 已读的记录数
OFS                输出域分隔符
ORS                输出记录分隔符
RS                 控制记录分隔符

  关于AWk命令的具体使用详解,请参考http://man.linuxde.net/awk。

Head 和 Tail(+从文章开头数,-从文章尾部数)

head命令是用来查看具体文件的前面几行的内容

tail命令是用来查看具体文件后面几行的内容

  -q 隐藏文件名

  -v 显示文件名

  -c<字节> 显示字节数

  -n<行数> 显示的行数

head -n 5 log2014.log  //文章前5行

head -n -2 log2014.log //将倒数第二行之前的内容都输出

tail [+ / - num ] [参数 ] 文件

tail -n +4 log2014.log //文章第四行之后的内容都输出(包含第四行)

tail -n -2 log2014.log //文章倒数两行的内容都输出

题目描述:

How would you print just the 10th line of a file?

For example, assume that file.txt has the following content:

Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10

  

Your script should output the tenth line, which is:

Line 10

Hint:

1. If the file contains less than 10 lines, what should you output?

2. There's at least three different solutions. Try to explore all possibilities.

题目大意:

输出一个文件的第10行。

思考:

1. 如果文件包含内容不足10行,应该输出什么?

2. 有至少3种不同的解决方法,尝试列举所有的可能方案

BASH脚本

解法一:使用awk

1 # Read from the file file.txt and output the tenth line to stdout.
2 awk 'NR == 10' file.txt #NR代表已读过的记录数

解法二:使用sed

1 # Read from the file file.txt and output the tenth line to stdout.
2 sed -n '10p' file.txt

解法三: 使用head和tail

1 # Read from the file file.txt and output the tenth line to stdout.
2 head -n +10 file.txt | tail -n -1   #这种对于文件内不足10行的,就会出现错误,文件有9行 则输出9 ,为8行则输出8
1 # Read from the file file.txt and output the tenth line to stdout.
2 tail -n +10 file.txt | head -n +1

 Transpose File(类似于矩阵转置问题)

 1 awk '{
 2     for(i=1;i<=NF;i++){
 3         if(NR==1){
 4             s[i]=$i;
 5         }else{
 6             s[i]=s[i]" "$i;
 7         }
 8     }
 9 }END{
10     for(i=1;i<=NF;i++)
11         print s[i];
12 }' file.txt
幸运之神的降临,往往只是因为你多看了一眼,多想了一下,多走了一步。
原文地址:https://www.cnblogs.com/strongYaYa/p/5684200.html