记录一下leecode上四道shell题
1、打印第十行
给定一个文本文件 file.txt
,请只打印这个文件中的第十行。
假设 file.txt
有如下内容:
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10
说明:
\1. 如果文件少于十行,你应当输出什么?
\2. 至少有三种不同的解法,请尝试尽可能多的方法来解题。
思路:判断文件行数,超过十行则打印第十行,不足十行则输出一个固定值(如”文本不足十行”或null)
统计行数的几种方法
root@mkp:/dbfile/xby# cat file.txt | wc -l
10
root@mkp:/dbfile/xby# sed -n "$=" file.txt
10
root@mkp:/dbfile/xby# grep -c "" file.txt
10
root@mkp:/dbfile/xby# awk 'END{print NR}' file.txt
10
root@mkp:/dbfile/xby# awk '{print NR}' file.txt |tail -n1
10
打印输出第十行
root@mkp:/dbfile/xby# awk 'NR == 10' file.txt #NR在awk中指行号
Line 10
root@mkp:/dbfile/xby# sed -n 10p file.txt #-n表示只输出匹配行,p表示Print
Line 10
root@mkp:/dbfile/xby# tail -n+10 file.txt |head -1 #tail -n +10表示从第10行开始输出
Line 10
代码及执行结果
row_num=$(cat file.txt | wc -l)
echo $row_num
if [ $row_num -lt 10 ];then
echo "The number of row is less than 10"
else
awk 'NR == 10' file.txt
fi
root@mkp:/dbfile/xby# sh line_count.sh
10
Line 10
2、转置文件
给定一个文件 file.txt
,转置它的内容。
你可以假设每行列数相同,并且每个字段由 ' '
分隔。
示例:
假设 file.txt 文件内容如下:
name age
alice 21
ryan 30
应当输出:
name alice ryan
age 21 30
**思路:**xargs多行变单行,统计好行数,用awk +print循环打印;
awk + print打印列,获取指定列的数据
root@mkp:/dbfile/xby# cat file.txt
name age
alice 21
ryan 30
root@mkp:/dbfile/xby# awk '{print $1}' file.txt
name
alice
ryan
root@mkp:/dbfile/xby# awk '{print $2}' file.txt
age
21
30
xargs多行变单行
xargs
这个命令,可以将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行。
root@mkp:/dbfile/xby# awk '{print $1}' file.txt
name
alice
ryan
root@mkp:/dbfile/xby# awk '{print $1}' file.txt |xargs
name alice ryan
如果有多列的情况下,输出只能按次序只能变成单行。也就是如下
root@mkp:/dbfile/xby# cat file.txt
name age
alice 21
ryan 30
root@mkp:/dbfile/xby# cat file.txt |xargs
name age alice 21 ryan 30
head + wc 获取列数
通过 head -n 命令可以获取文件指定行数的内容,再使用 wc -w 即可获取当前行的所有列数。由于本题每行列数相同,因此我们取第一行即可
root@mkp:/dbfile/xby# cat file.txt |head -1 |wc -w
2
最终代码,用循环输出
# 获取第一行,然后用wc来获取列数
COLS=`head -1 file.txt | wc -w`
# 使用awk依次去输出文件的每一列的参数,然后用xargs做转置
for (( i = 1; i <= $COLS; i++ )); do
# 这里col就是在代码里要替换的参数,而它等于$i
awk -v col=$i '{print $col}' file.txt | xargs
done
3、有效电话号码
给定一个包含电话号码列表(一行一个电话号码)的文本文件 file.txt,写一个单行 bash 脚本输出所有有效的电话号码。
你可以假设一个有效的电话号码必须满足以下两种格式: (xxx) xxx-xxxx 或 xxx-xxx-xxxx。(x 表示一个数字)
你也可以假设每行前后没有多余的空格字符。
示例:
假设 file.txt
内容如下:
987-123-4567
123 456 7890
(123) 456-7890
你的脚本应当输出下列有效的电话号码:
987-123-4567
(123) 456-7890
思路:
题目的核心是匹配符合规则的字符串,因为规则比较单一,所以使用正则表达式来检索符合要求的字符串即可。
使用正则表达式描述规律
正则表达式的重点有三:特殊字符、限定字符、定位符
熟练掌握这三点,大部分的正则表达都不在话下~
特殊字符:勿忘加上转义符’’
限定字符:限定字符出现的次数,掌握它也就get了精华,麻麻再也不用担心我读不懂漂亮的表达式了。
定位符:稍加理解,就能get到的好技巧
表达 xxx-xxx-xxxx
^[0-9][0-9][0-9]-[0-9][0-9][0-9]-[0-9][0-9][0-9][0-9]$
使用限定符来限定数字出现的次数,优化为如下表达
^[0-9]{3}-[0-9]{3}-[0-9]{4}$
同时表示xxx-xxx-xxxx和 (xxx) xxx-xxxx
使用特殊字符()和|。用()来标记一个表达式,使用|来指明两项之间的任意选择。
^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$
grep与awk
grep -P '^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$' file.txt
awk '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/' file.txt
gawk '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/' file.txt
4、统计词频
写一个 bash 脚本以统计一个文本文件 words.txt 中每个单词出现的频率。
为了简单起见,你可以假设:
words.txt只包括小写字母和 ’ ’ 。
每个单词只由小写字母组成。
单词间由一个或多个空格字符分隔。
示例:
假设 words.txt
内容如下:
the day is sunny the the
the sunny is is
你的脚本应当输出(以词频降序排列):
the 4
is 3
sunny 2
day 1
题解
root@mkp:/dbfile/xby# cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -nr | awk '{ print $2, $1 }'
the 4
is 3
sunny 2
day 1
解题步骤
切割
tr
命令用于转换或删除文件中的字符
-s:缩减连续重复的字符成指定的单个字符
cat Words.txt| tr -s ' ' '\n'
排序单词
cat Words.txt| tr -s ' ' '\n' | sort
统计单词出现次数
uniq
命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。
-c:在每列旁边显示该行重复出现的次数。
cat Words.txt| tr -s ' ' '\n' | sort | uniq -c
排序单词出现次数
-r:以相反的顺序来排序
-n: 按数字排序(当单词的出现次数大于10时,sort 需要考虑按数字排序,而非默认的按 ascii 码排序)
cat Words.txt| tr -s ' ' '\n' | sort | uniq -c | sort -nr
打印
cat Words.txt| tr -s ' ' '\n' | sort | uniq -c | sort -nr | awk '{print $2, $1}'