算法-关于LeetCode的四道shell编程

最近在面试中碰到了一些关于linux下一些简单命令的操作和awk sed等文本编辑器的使用,借助力扣上4道shell题目进行学习,当然也参考一些别人的答案作为总结,欢迎补充交流,如有侵权,联系删除

问题一:第十行(考查打印特定行)

示例:
假设 file.txt 有如下内容:
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10
你的脚本应当显示第十行:
Line 10

以下三种方式均可以运行通过:

1. grep -n "" file.txt | grep -w '10' | cut -d: -f2
2. sed -n '10p' file.txt
3. awk '{if(NR==10){print $0}}' file.txt

但是考虑到说明中行数不足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 '{if(NR==10){print $0}}' file.txt
fi

补充:其中文件行数row_num可以使用如下几种方式获取

1. awk '{print NR}' file.txt | tail -n1
2. awk 'END{print NR}' file.txt 
3. grep -nc "" file.txt
4. grep -c "" file.txt 
5. grep -vc "^$" file.txt 
6. grep -n "" file.txt|awk -F: '{print '}|tail -n1 | cut -d: -f1
7. grep -nc "" file.txt
8. sed -n "$=" file.txt 
9. wc -l file.txt 
  10 file.txt
  cat file.txt | wc -l
10. wc -l file.txt | cut -d' ' -f1

问题二:有效的电话号码(考查正则表达式)

给定一个包含电话号码列表(一行一个电话号码)的文本文件 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

预备知识:
1.特殊字符表达:

算法-关于LeetCode的四道shell编程_第1张图片

2.限定符表达:

注意: 表含义中的出现次数:限定符前面字符的出现次数。
算法-关于LeetCode的四道shell编程_第2张图片

3.定位符:

算法-关于LeetCode的四道shell编程_第3张图片

关于grep的4中写法:

1. cat file.txt  | grep -P "^\([0-9]{3}\) [0-9]{3}-[0-9]{4}$|^[0-9]{3}-[0-9]{3}-[0-9]{4}$"
2. grep -P '^(\(\d{3}\) |\d{3}-)\d{3}-\d{4}$' file.txt
3. grep -P '^([(]\d{3}[)] |\d{3}-)\d{3}-\d{4}$' file.txt
4. grep -E '^(\([0-9]{3}\) |[0-9]{3}-)[0-9]{3}-[0-9]{4}$' file.txt

注意:""不要丢了,其中的空格,()是普通字符," "不要丢了
^:表示行首,以...开始,这里表示以(xxx) 或者xxx-开始,注意空格
():选择操作符,要么是([0-9]{3}) ,要么是[0-9]{3}-
|:或者连接操作符,表示或者
[]:单字符占位,[0-9]表示一位数字
{n}:匹配n位,[0-9]{3}匹配三位连续数字
$:表示行尾,结束

关于awk '/正则表达式/{print $0}'的3中写法:

1. awk '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/' file.txt
2. gawk '/^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$/' file.txt
3. awk '/^\([0-9]{3}\)\s[0-9]{3}\-[0-9]{4}$|^[0-9]{3}\-[0-9]{3}\-[0-9]{4}$/{print $0}' file.txt

其中3中的 \s表示空格


问题三:有效词频

写一个 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

方法一:

解题思路:
取出每个单词; NF=一行有多少列, for循环一个一个取出来, 每行打印一个
把相同的单词排在一起: sort
合并相同的单词,并标记数量: uniq -c; c代表count
按照数字大小降序排列: sort排序; -$1 按照$1 count来排序; -r 降序
先打印单词, 再打印数字: awk print $2,$1
代码:

awk '{for(i=0;i
方法二:

解题思路:
xargs 分割字符串 -n 1表示每行输出一个 可以加-d指定分割
要使用uniq统计词频需要被统计文本相同字符前后在一起,所以先排序 uniq -c 表示同时输出出现次数
sort -nr 其中-n表示把数字当做真正的数字处理(当数字被当做字符串处理,会出现11比2小的情况)
代码:

cat words.txt | xargs -n 1 | sort | uniq -c | sort -nr | awk '{print $2" "$1}'
方法三:

获取words.txt的内容
将空格换成换行符,让每一个单词单独成为一列
根据字母顺序进行排序
使用uniq -c统计频次
逆序排序
过滤空的字符,并将结果输出
代码:

cat words.txt | tr ' ' '\n' | sort | uniq -c | sort -r | awk '$2!="" {print $2" "$1}'

问题四:转置文件

给定一个文件 file.txt,转置它的内容。
你可以假设每行列数相同,并且每个字段由 ' ' 分隔.
示例:
假设 file.txt 文件内容如下:
name age
alice 21
ryan 30

应当输出:
name alice ryan
age 21 30

附上感觉特别清晰的一篇讲解:

链接

以下为博客内容:

awk命令:

awk是一个报告生成器,它拥有强大的文本格式化的能力。它是由Alfred Aho 、Peter Weinberger 和 Brian Kernighan这三个人创造的,awk由这个三个人的姓氏的首个字母组成。

awk的基本语法是 awk [options] 'Pattern{Action}' file

从一个最简单的命令作为start,省略[options]和Pattern,将Action设置成最简单的print:

$ echo abc > test.txt
$ awk '{print}' test.txt

abc
这就是最最简单的awk用法:使用awk命令对文本test.txt(的每一行)进行处理,处理的动作是print

解法:
awk '{
    for (i=1;i<=NF;i++){
        if (NR==1){  
            res[i]=$i
        }
        else{
            res[i]=res[i]" "$i
        }
    }
}END{
    for(j=1;j<=NF;j++){
        print res[j]
    }
}' file.txt

解析:
awk是一行一行地处理文本文件,运行流程是:

  1. 先运行BEGIN后的{Action},相当于表头
  2. 再运行{Action}中的文件处理主体命令
  3. 最后运行END后的{Action}中的命令

有几个经常用到的awk常量:NF是当前行的field字段数;NR是正在处理的当前行数。

注意到是转置,假如原始文本有m行n列(字段),那么转置后的文本应该有n行m列,即原始文本的每个字段都对应新文本的一行。我们可以用数组res来储存新文本,将新文本的每一行存为数组res的一个元素。

在END之前我们遍历file.txt的每一行,并做一个判断:在第一行时,每碰到一个字段就将其按顺序放在res数组中;从第二行开始起,每碰到一个字段就将其追加到对应元素的末尾(中间添加一个空格)。

文本处理完了,最后需要输出。在END后遍历数组,输出每一行。注意printf不会自动换行,而print会自动换行。

你可能感兴趣的:(程序员)