写在前面:

  • 每道shell脚本练习题都可以使用while、for、do等循环配合read,printf的方式解题,通过这种编程式的思维解题(类似C语言,通过变量与函数解题)。而shell中本身就提供了很多很强大的命令工具,如awk,sed,grep等。

  • 相信通过编写shell脚本函数的方式都能很轻易的解题,而本篇文章的重点不在于此,本篇文章主要是想讨论能否尽可能的利用shell中提供的命令工具解题。通过这些例题,更好的熟悉和掌握shell中常用的一些命令工具。

  • 每道题提供多种解法,通过多种shell命令组合解题,如果您有更好的解法也欢迎在评论区留言评论。在每个命令第一出现的地方,都附加有命令的参考资料。另外这里提供两个Linux命令查询的工具。

  • 附:Linux命令查询工具:

    1. https://www.linuxcool.com/
    2. https://wangchujiang.com/linux-command/

Tips: 在多次提交的过程中发现(牛客网的提交方案中),实际上我们提交的代码是被保存在了一个脚本文件中,在运行时执行了 script.sh < ./nowcoder.txt命令.

  • 因此,我们某些命令是可以省略的。比如输出文件内容可以是 cat ./nowcoder.txt 的常规输出方法;
  • 或者我们可以使用执行脚本时,传入的命令行参数实现 cat $1 输出;
  • 更或者我们直接使用一个 cat 命令即可实现。

文章目录

  • 一、简单题
    • 1. 统计文件的行数
      • 方法一:使用wc命令,统计行数
      • 方法二:使用awk工具,处理文本
      • 方法三:使用cat或nl命令,添加行号
      • 方法四:使用grep文本搜索工具
      • 方法五:使用sed文本编辑器
    • 2. 打印文件的最后5行
      • 方法一:使用tail,显示文件末尾n行
      • 方法二:使用awk编程语言,处理文本和数据
      • 方法三:使用tac命令,反序输出
  • 二、中等题
    • 3. 输出7的倍数
      • 方法一:使用seq以指定增量从首数开始打印数字到尾数
      • 方法二:使用shell中的for循环
      • 方法三:使用awk工具内提供的循环
    • 4. 输出第5行内容
      • 方法一:使用sed文本编辑
      • 方法二:使用head+tail命令
      • 方法三:显示行号,提取对应行输出
      • 方法四:使用awk工具,处理文本
    • 5. 打印空行的行号
      • 方法一:使用awk工具,正则匹配&关系表达式
      • 方法二:使用cat命令,显示行号
      • 方法三:使用grep过滤,正则过滤空行
    • 6. 去掉空行
      • 方法一:使用tr命令,字符压缩替换工具
      • 方法二:使用awk工具,正则&函数
      • 方法三:使用grep文本搜索工具
      • 方法四:使用sed流式文本编辑器
      • 方法五:使用printf格式化输出工具
      • 方法六:使用xargs命令工具
    • 13. 去掉所有包含this的语句
      • 方法一:使用sed文本编辑工具
      • 方法二:使用awk工具,正则匹配
      • 方法三:使用grep文本搜索工具
  • 三、较难题
    • 7. 打印字母数小于8的单词
      • 方法一:使用xargs命令工具
      • 方法二:使用awk工具,关系表达式
      • 方法三:将行转为列,使用awk工具处理
      • 方法四:使用shell中的for循环
    • 8. 统计所有进程占用内存大小的和
      • 方法一:使用awk工具
      • 方法二:提取数据,对一列求和
      • 方法三:提取数据,对一行数据求和
    • 9. 统计每个单词出现的个数
      • 方法一:使用[sort] | [uniq] | [awk]
    • 10. 第二列是否有重复
      • 方法一:使用sort & uniq 组合命令
      • 方法二:使用awk工具
    • 11. 转置文件的内容
      • 方法一:使用xargs进行‘列转行’
      • 方法一:使用tr进行‘列转行’
      • 方法三:使用awk工具
    • 12. 打印每一行出现的数字个数
      • 方案一:使用sed & awk组合工具
      • 方法二:使用awk工具内置命令gsub,正则替换
      • 方法三:使用tr删除字符集
      • 方法四:编写shell脚本函数,类似C语言处理数据
    • 14. 求平均值
      • 方法一:使用awk工具
      • 方法二:使用bc命令工具
      • 方法三:通过while循环处理
    • 15. 去掉不需要的单词
      • 方法一:使用grep文本搜索工具
      • 方法二:使用sed流失文本工具
      • 方法三:使用awk工具

~~~~ 分割线 ~~~~


一、简单题

1. 统计文件的行数

  • 题目链接: 【牛客网 | 统计文件的行数】
  • 题目描述
    写一个 bash脚本以输出一个文本文件 nowcoder.txt中的行数
    示例:
    假设 nowcoder.txt 内容如下:
#include <iostream>
using namespace std;
int main()
{int a = 10;int b = 100;cout << "a + b:" << a + b << endl;return 0;
}

你的脚本应当输出:9

方法一:使用wc命令,统计行数
  • 参考资料《wc - 统计文件的字节数、字数、行数》
  • 直接使用 wc -l ./nowcoder.txt 会输出“总行号 文件名”,我们可以使用以下方法来完成此题。
  1. 使用输入重定向与wc命令进行统计行号
wc -l < ./nowcoder.txt
  1. 统计cat命令输出的内容中的行号
cat ./nowcoder.txt | wc -l
  1. 使用awk工具,只输出第一列
wc -l ./nowcoder.txt | awk '{print $1}'
方法二:使用awk工具,处理文本
  • 参考资料《awk - 文本和数据进行处理的编程语言》
  1. 打印每一行的行号,只取最后一行
awk '{print NR}' ./nowcoder.txt |tail -n 1
  1. 直接打印最后一行的行号
awk 'END{print NR}' nowcoder.txt
方法三:使用cat或nl命令,添加行号
  • 参考资料《nl - 为每一个文件添加行号》
  • cat -n file_name 添加行号
  1. 给文件添加行号后,取最后一行第一列
cat -n ./nowcoder.txt | tail -n1 | awk '{print $1}'
#或
cat -n ./nowcoder.txt | awk 'END{print $1}'
方法四:使用grep文本搜索工具
  • 参考资料《grep - 强大的文本搜索工具》
  1. 使用-c参数,只输出匹配行的数量
grep -c "" ./nowcoder.txt
  1. 使用-n参数,列出所有的匹配行及行号。格式为 “行号:内容”。这里使用awk工具处理文本格式
grep -n "" ./nowcoder.txt  | awk -F ":" '{print $1 }' | tail -n 1
方法五:使用sed文本编辑器
  • 参考资料《sed - 功能强大的流式文本编辑器》
  • 参数说明
    • -n 如果test被匹配,则移动到匹配行的下一行
    • = 打印当前行号
    • $ 匹配行结束
sed -n '$=' ./nowcoder.txt

2. 打印文件的最后5行

  • 题目链接:【牛客网 | 打印文件的最后5行】
  • 题目描述
    经常查看日志的时候,会从文件的末尾往前查看,于是请你写一个 bash脚本以输出一个文本文件 nowcoder.txt中的最后5行
    示例:
    假设 nowcoder.txt 内容如下:
#include<iostream>
using namespace std;
int main()
{int a = 10;
int b = 100;
cout << "a + b:" << a + b << endl;
return 0;
}

你的脚本应当输出:

int a = 10;
int b = 100;
cout << "a + b:" << a + b << endl;
return 0;
}
方法一:使用tail,显示文件末尾n行

参考资料《tail - 在屏幕上显示指定文件的末尾若干行》

tail -n5 ./nowcoder.txt
方法二:使用awk编程语言,处理文本和数据
  • 参考资料《awk - 文本和数据进行处理的编程语言》
  1. 求出总行数,减去5即为倒数第5行。从该行打印至末行即可
total=`awk 'END{print NR}' ./nowcoder.txt`       # 总行数# -v 定义awk变量
awk -v val=$(expr $total - 5) 'NR>val' ./nowcoder.txt
  1. 使用awk内的循环
  • awk支持while、do…while、for循环等操作,还可以定义变量。我们完全可以把awk的内部当做一个函数进行处理,只需编写出适合的代码即可完成此题。
awk '{arr[NR]=$0} END { i=NR-5+1; do{ print arr[i]; i++}while(i <= NR);  }' ./nowcoder.txt
方法三:使用tac命令,反序输出
  • 参考资料 《tac - 连接多个文件并以行为单位反向打印到标准输出》
  1. tac是cat命令的反序形式,功能也与cat功能相似,成反序输出
tac ./nowcoder.txt | head -n5 | tac
  1. 同理,使用相同的思路,我们也可以使用cat命令给文本带上行号,然后使用sort根据行号逆序排序,取排序后的前5行,然后在正序。过滤掉行号输出即可。
cat -n  ./nowcoder.txt | sort -n$1 -r | head -n5 | sort | awk '{$1=""; print $0}'

二、中等题

3. 输出7的倍数

  • 题目链接:【牛客网 | 输出7的倍数】
  • 题目描述
    写一个 bash脚本以输出数字 0 到 500 中 7 的倍数(0 7 14 21…)的命令
方法一:使用seq以指定增量从首数开始打印数字到尾数
  • 参考资料《seq - 以指定增量从首数开始打印数字到尾数》
  1. 生成步长为7的,范围为 0~500 的数列
seq 0 7 500
方法二:使用shell中的for循环
  • shell中主要支持三种循环,while、for、until。
  1. 类似C语言风格的for循环写法for((exp1; exp2; exp3)) do ... done
# for((i=0; i<500; i+=7)); do  echo $i; done
for((i=0; i<500; i+=7))
doecho $i
done
  1. for in 循环,类似python风格 for var in list do ... done
# for i in {0..500..7}; do  echo $i ; done
for i in {0..500..7}
do  echo $i
done
方法三:使用awk工具内提供的循环
  1. awk内部支持for循环,通过待处理文本 “0 500 7” 便可轻松获得7的倍数
awk '{i=0; while(i<=500){print i;i+=7}}'
#echo "0 500 7" | awk '{i=$1; while(i<=$2){print i;i+=$3}}'

4. 输出第5行内容

  • 题目链接:【牛客网 | 输出第5行内容】
  • 题目描述
    写一个 bash脚本以输出一个文本文件 nowcoder.txt 中第5行的内容。
    示例:
    假设 nowcoder.txt 内容如下:
welcome
to
nowcoder
this
is
shell
code

你的脚本应当输出:is

方法一:使用sed文本编辑
  • 参考资料《sed - 功能强大的流式文本编辑器》
sed -n 5p nowcoder.txt
方法二:使用head+tail命令
  • head命令 – 显示文件开头内容
  • tail命令 – 查看文件尾部内容
  1. 使用head提取出文本前5行,再通过tail查看最后一行的内容
head -5 ./nowcoder.txt | tail -1
#head -n5 ./nowcoder.txt | tail -n1
  1. 使用tail -n +5 显示5行以后的内容,再通过head提取第一行内容
tail ./nowcoder.txt -n +5 | head -n 1
方法三:显示行号,提取对应行输出
  1. cat -n参数可以显示行号,使用awk提取出对应文本
cat -n ./nowcoder.txt | awk '$1==5 {print $2}'
方法四:使用awk工具,处理文本
  1. 直接使用awk内置变量NR 匹配到第5行,进行输出。
awk 'NR==5' ./nowcoder.txt
#awk 'NR==5 {print $0}' ./nowcoder.txt

5. 打印空行的行号

  • 题目链接:【牛客网 | 打印空行的行号】
  • 题目描述
    写一个 bash脚本以输出一个文本文件 nowcoder.txt中空行的行号,可能连续,从1开始
    示例:
    假设 nowcoder.txt 内容如下:
a
bcdef

你的脚本应当输出:

357910

注意:空行与含有空格的行不同,必要是可使用cat -A查看。

方法一:使用awk工具,正则匹配&关系表达式
  1. 当前行为空时,打印行号
awk '{if($0 == "") {print NR}}' ./nowcoder.txt
  1. 正则匹配到空行时,打印行号
awk '/^$/ {print NR}' ./nowcoder.txt 
方法二:使用cat命令,显示行号
  1. 在文本显示行号后,选中第2列没有数据的行,输出他们的首列即可
cat -n ./nowcoder.txt | awk '$2=="" {print $1}'
方法三:使用grep过滤,正则过滤空行
  • 统计文本中空行个数 grep -c ^$ file_name,非空行grep -c ^[^$] file_name
  • 带行号的输出空行 grep -n ^$,注意:输出格式为 “行号:数据”
  • 使用awk工具或cut工具提取第一列,即只含有行号的列
grep -n ^$ ./nowcoder.txt | awk -F: '{print $1}'
#grep -n ^$ ./nowcoder.txt | cut -f1 -d":"

6. 去掉空行

  • 题目链接:【牛客网 | 去掉空行】
  • 题目描述
    写一个 bash脚本以去掉一个文本文件 nowcoder.txt中的空行
    示例:
    假设 nowcoder.txt 内容如下:
abc567aaa
bbbccc

你的脚本应当输出:

abc567aaabbbccc
方法一:使用tr命令,字符压缩替换工具
  • 参考资料 《tr - 将字符进行替换压缩和删除》
cat ./nowcoder.txt | tr -s '\n'
方法二:使用awk工具,正则&函数
  1. 正则
awk '/^[^$]/' ./nowcoder.txt
  1. 该行不为空
awk '$0!=""' ./nowcoder.txt
  1. 行长度不为0
awk 'length!=0' ./nowcoder.txt
方法三:使用grep文本搜索工具
  1. 正则,匹配非空行
grep "^[^$]" ./nowcoder.txt
  1. \s匹配空白字符,等价于[ \f\n\r\t\v]等,而\S匹配非空白字符,等价于 [^ \f\n\r\t\v]
grep '\S' nowcoder.txt
方法四:使用sed流式文本编辑器
  1. 去除空行。-d 参数,删除选择的行
sed '/^$/d' ./nowcoder.txt
方法五:使用printf格式化输出工具
  • 参考资料 《printf - 格式化并输出结果》
printf '%s\n' $(cat ./nowcoder.txt)
方法六:使用xargs命令工具
  • 参考资料 《xargs - 给其他命令传递参数的一个过滤器》
cat ./nowcoder.txt | xargs -n1 echo

13. 去掉所有包含this的语句

  • 题目链接:【牛客网 | 去掉所有包含this的语句】
  • 题目描述
    写一个 bash脚本以实现一个需求,去掉输入中含有this的语句,把不含this的语句输出
    示例:
    假设输入如下:
this is your bag
is this your bag?
to the degree or extent indicated.
there was a court case resulting from this incident
welcome to nowcoder

你的脚本获取以上输入应当输出:

to the degree or extent indicated.welcome to nowcoder

说明:
你可以不用在意输出的格式,包括空格和换行

方法一:使用sed文本编辑工具
  1. sed ‘/tset/d’ 删除含有“test”的行
sed '/this/d'

相关扩展:

  • 删除文件中所有开头是test的行:sed '/^test/'d file
  • 删除空白行:sed '/^$/d' file
  • 删除文件的第2行:sed '2d' file
  • 删除文件的第2行到末尾所有行:sed '2,$d' file
  • 删除文件最后一行:sed '$d' file
方法二:使用awk工具,正则匹配
  • /正则表达式/:使用通配符的扩展集。
  • 模式匹配表达式:用运算符~(匹配)和!~(不匹配)。
awk '$0!~/this/ {print $0}'
# awk '$0!~/this/'

方法三:使用grep文本搜索工具
  1. 输出除之外的所有行 -v 选项
grep -v "this"

三、较难题

7. 打印字母数小于8的单词

  • 题目链接:【牛客网 | 打印字母数小于8的单词】
  • 题目描述
    写一个 bash脚本以统计一个文本文件 nowcoder.txt中字母数小于8的单词。
    示例:
    假设 nowcoder.txt 内容如下:
    how they are implemented and applied in computer
    你的脚本应当输出:
howtheyareandappliedin

说明:
不要担心你输出的空格以及换行的问题

方法一:使用xargs命令工具
cat ./nowcoder.txt | xargs -n1 echo
方法二:使用awk工具,关系表达式
awk '{for(i=1;i<=NF;i++){if(length($i)<8){print $i}}}' nowcoder.txt
方法三:将行转为列,使用awk工具处理
  1. tr+awk
cat ./nowcoder.txt | tr ' ' '\n' | awk 'length<8'
  1. printf+awk
printf "%s\n" $(cat ./nowcoder.txt) | awk 'length<8'
  1. xargs
cat ./nowcoder.txt | xargs -n1 | awk 'length<8'
方法四:使用shell中的for循环
#for s in $(cat ./nowcoder.txt); do  if [ ${#s} -lt 8 ]; then echo $s; fi; done
for s in $(cat ./nowcoder.txt)
doif [ ${#s} -lt 8 ]
thenecho $s
fi
done

8. 统计所有进程占用内存大小的和

  • 题目链接:【牛客网 | 统计所有进程占用内存大小的和】
  • 题目描述
    假设 nowcoder.txt 内容如下:
 USER      | PID | %CPU |%MEM | VSZ  | RSS | TTY | STAT |    TIME      | COMMAND
root           2   0.0   0.0       0      0  ?     S     9月25   0:00    [kthreadd]
root           4   0.0   0.0       0      0  ?     I<    9月25   0:00    [kworker/0:0H]
web         1638   1.8   1.8  6311352 612400 ?     Sl    10月16  21:52   test
web         1639   2.0   1.8  6311352 612401 ?     Sl    10月16  21:52   test
tangmiao-pc 5336   0.0   1.4  9100240 238544 ??    S    3:09下午 0:31.70  /Applications

以上内容是通过ps aux | grep -v ‘RSS TTY’ 命令输出到nowcoder.txt文件下面的
请你写一个脚本计算一下所有进程占用内存大小的和:

分析

首先我们需要了解ps命令的输出的字段参数的意义。

  • ps -aux 显示所有包含其他使用者的行程, 输出格式为 :
> USER      PID     %CPU             %MEM                 VSZ                     RSS
> 进程拥有者  pid   占用的 CPU 使用率  占用的物理内存的使用率 占用的虚拟内存大小(单位KB) 占用的实际物理内存大小(单位KB)TTY                   STAT                 START          TIME                COMMAND进程在哪一个终端上运行      进程的状态            行程开始时间   进程占用的CPU运算时间    所执行的指令本地进制太终端tty1~ty7  R(运行)、S(睡眠)、T(停止)...

题目要求计算的是进程真实占用的物理内存,即nowcoder.txt中的第6列数据。

方法一:使用awk工具
awk '{sum+=$6} END{print sum}' ./nowcoder.txt

使用awk解此题是最方便高效的,不过我们也可以尝试不使用awk工具解此题。其中方法2方法3的主要思路都是将数据提取为一行或一列,让后对齐求和即可。而我们需要做的只是尽可能多的使用不同的方法完成“数据求和”这一步骤。

下面的shell求和方法多有参考stackoverflow的这篇讨论《Shell command to sum integers, one per line?》

方法二:提取数据,对一列求和
  • echo命令:输出指定的字符串或者变量
  • tr:字符串压缩和替换
  • cut:从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出
  • bc:算术操作精密运算工具
  1. 对一列数据求和
echo `cat ./nowcoder.txt | tr -s ' ' | cut -d' ' -f 6 | tr '\n' '+' `0 | bc

提取第6列数据,通过tr命令将其替换成带加号表达式。

echo `cat ./nowcoder.txt | tr -s ' ' | cut -d' ' -f 6 | tr '\n' '+' `0 | bc
=>    echo  "0+0+612400+612401+238544+"0  |  bc
=>    echo  "0+0+612400+612401+238544+0"  |  bc
  1. 类似的还有
  • perl语言解释器,执行perl脚本
cat ./nowcoder.txt | tr -s ' ' | cut -d' ' -f 6 | perl -lpe '$c+=$_}{$_=$c'
方法三:提取数据,对一行数据求和

方法二将数据提取至一列,我们可以通过 xargs命令将其转换为一行后再行操作。

  1. 通过sed与bc工具计算表达式的值
cat ./nowcoder.txt | tr -s ' ' | cut -d' ' -f 6 | xargs | sed -e 's/\ /+/g' | bc
  • 以上步骤可主要分为三步:

    • 1,提取第6列至nums中, nums+=`cat ./nowcoder.txt | tr -s ' ' | cut -d' ' -f 6`

      • tr -s ' ' 删除重复出现的空格,只保留一个
      • cut -d ' ' -f 6 提取第6列的数据
    • 2,将列转为行之后,通过sed工具计算, echo $nums | xargs | sed -e 's/\ /+/g'
      • echo $nums | xargs ,列转行
      • sed命令及参数 sed -e 's/\ /+/g',此scriptfile的作用是,将空格替换成‘+’。
      • -e 指定的script来处理输入的文本文件,在scriptfile 中各参数意义为:
        • 使用后缀 /g 标记会替换每一行中的所有匹配
        • 替换操作:s命令,使用前缀 s/ 标记
        • 字符 / 在sed中作为定界符使用,也可以使用任意的定界符:'s|\ |+|g''s:\ :+:g'
    • 3,替换完成之后,数据为 0+0+612400+612401+238544 ,我们通过bc命令计算表达式的值。

9. 统计每个单词出现的个数

  • 题目链接:【牛客网 | 统计每个单词出现的个数】
  • 题目描述
    写一个 bash脚本以统计一个文本文件 nowcoder.txt 中每个单词出现的个数。
    为了简单起见,你可以假设:
    nowcoder.txt只包括小写字母和空格。
    每个单词只由小写字母组成。
    单词间由一个或多个空格字符分隔。
    示例:
    假设 nowcoder.txt 内容如下:
welcome nowcoder
welcome to nowcoder
nowcoder

你的脚本应当输出(以词频升序排列):

to 1
welcome 2
nowcoder 3

说明:
不要担心个数相同的单词的排序问题,每个单词出现的个数都是唯一的。

方法一:使用[sort] | [uniq] | [awk]
  • 参考资料 《uniq - 显示或忽略重复的行》
  1. 通过 排序 | 去重 | 打印三步即可完成
cat ./nowcoder.txt | xargs -n1 | sort | uniq -c | sort -n$1 | awk '{print $2,$1}'
# 或
cat ./nowcoder.txt | tr -s ' ' '\n' | sort | uniq -c | sort -n$1 | awk '{print $2,$1}'

步骤解析:

    1. 行转列。使用 xargs -n1 或 tr -s ’ ’ ‘\n’ 都可以。
$ cat ./nowcoder.txt | tr -s ' ' '\n'
welcome
nowcoder
welcome
to
nowcoder
nowcoder
    1. 去重,并统计每个词出现的次数。需要注意的是,uniq命令只对相邻行去重和统计次数。
      因此,在去重前需要先排一次序。
$ cat ./nowcoder.txt | tr -s ' ' '\n' | sort | uniq -c3 nowcoder1 to2 welcome
    1. 按要求打印输出对应列即可,这里我们选择使用awk工具,先输出第2列,再输出第1列。
      注意,题目要求按照词频降序排列,所以这里我们再使用一次排序。
$ cat ./nowcoder.txt | tr -s ' ' '\n' | sort | uniq -c | sort -r -n $1 | awk '{print $2,$1}'
nowcoder 3
welcome 2
to 1

10. 第二列是否有重复

  • 题目链接:【牛客网 | 第二列是否有重复】
  • 题目描述
    给定一个 nowcoder.txt文件,其中有3列信息,如下实例,编写一个shell脚本来检查文件第二列是否有重复,且有几个重复,并提取出重复的行的第二列信息:
    实例:
20201001 python 99
20201002 go 80
20201002 c++ 88
20201003 php 77
20201001 go 88
20201005 shell 89
20201006 java 70
20201008 c 100
20201007 java 88
20201006 go 97

结果:

2 java
3 go
方法一:使用sort & uniq 组合命令
  • sort 及其参数

    • -n是按照数字大小排序
    • -r是以相反顺序
    • -k是指定需要排序的栏位
    • -t指定栏位分隔符为冒号
cat ./nowcoder.txt | sort -rk 2 | cut -d' '  -f 2 | uniq -cd

步骤解析:

    1. 排序,是相同的列可以相邻
$ cat ./nowcoder.txt | sort -rk 2
20201005 shell 89
20201001 python 99
20201003 php 77
20201007 java 88
20201006 java 70
20201006 go 97
20201001 go 88
20201002 go 80
20201002 c++ 88
20201008 c 100
    1. 按题目要求,截取第2列字段
$ cat ./nowcoder.txt | sort -rk 2 | cut -d ' ' -f 2
shell
python
php
java
java
go
go
go
c++
c
    1. 去重,并统计词频。使用 -d 选项打印临近的重复行
$ cat ./nowcoder.txt | sort -rk 2 | cut -d ' ' -f 2 | uniq -cd2 java3 go
方法二:使用awk工具
  1. 与上面同理,这里使用了awk的提取列字段的功能
cat ./nowcoder.txt | awk '{print $2}' | sort -r | uniq -cd

11. 转置文件的内容

  • 题目链接:【牛客网 | 转置文件的内容】
  • 题目描述
    写一个 bash脚本来转置文本文件nowcoder.txt中的文件内容。
    为了简单起见,你可以假设:
    假设每行列数相同,并且每个字段由空格分隔
    示例:
    假设 nowcoder.txt 内容如下:
job salary
c++ 13
java 14
php 12

你的脚本应当输出(以词频升序排列):

job c++ java php
salary 13 14 12
方法一:使用xargs进行‘列转行’
cat ./nowcoder.txt | cut -d' ' -f 1 | xargs
cat ./nowcoder.txt | cut -d' ' -f 2 | xargs
方法一:使用tr进行‘列转行’
cat ./nowcoder.txt | cut -d' ' -f 1 | tr ' ' '\n'
cat ./nowcoder.txt | cut -d' ' -f 2 | tr ' ' '\n'
方法三:使用awk工具
  1. 先输出第1列的数据,同时将第2列的数据保存在数组中,等到第1列数据输入完成之后,遍历数组元素输出第2列数据
awk '{;printf  $1" "; str[NR]=$2 } END{print ""; for(i=1; i<=NR; i++){printf str[i]" "} print ""}' ./nowcoder.txt
  1. 简化。输出第一列数据的同时,将第2列数据保存在buff中,并拼接成一个字符串。
awk '{  printf  $1" "; buff=$2" "; str=str""buff } END{ print ""; print str""}' ./nowcoder.txt#或者
awk '{  printf  $1" "; buff=buff$2" " } END{ print ""; print buff}' ./nowcoder.txt

12. 打印每一行出现的数字个数

  • 题目链接:【牛客网 | 打印每一行出现的数字个数】
  • 题目描述
    写一个 bash脚本以统计一个文本文件 nowcoder.txt中每一行出现的1,2,3,4,5数字个数并且要计算一下整个文档中一共出现了几个1,2,3,4,5数字数字总数。
    示例:
    假设 nowcoder.txt 内容如下:
a12b8
10ccc
2521abc
9asf

你的脚本应当输出:

line1 number: 2
line2 number: 1
line3 number: 4
line4 number: 0
sum is 7

说明:
不要担心你输出的空格以及换行的问题

方案一:使用sed & awk组合工具
  • sed、grep、awk都支持正则表达式,而此题使用正则表达式将会非常简单。
  • 如果使用grep配合awk也能达到统计每行个数的效果,但不符合题目要求的是,grep会过滤掉不含匹配项的行。如此以来,最终的结果就会缺少一个“line4 number: 0”答案。因此我们选择使用sed工具。
l$ grep '[1-5]*' ./nowcoder.txt -o
12
1
2521
  1. 使用sed将文本处理为每行仅有 1~5 范围的数组,再使用awk工具进行输出。
sed s/[^1-5]//g nowcoder.txt | awk '{print "line"NR" number: "length; total+=length} END{print "sum is "total}' 

步骤解析:

    1. 使用sed处理文本,格式为 sed s/待替换文本/替换内容/g
$ sed s/[^1-5]//g nowcoder.txt
12
1
2521# 注意:这里有一个空行
    1. 使用awk内置函数length输出每行长度即可。
方法二:使用awk工具内置命令gsub,正则替换
  • gsub( Ere, Repl, [ In ] ),匹配正则表达式Ere的字符被替换为Repl,储存在[In]中
awk -v sum=0 '{gsub(/[^1-5]/,"",$0); print "line"NR" number: "length;sum+=length} END{print "sum is "sum}' ./nowcoder.txt 

步骤解析:

    1. 使用gsub() 将文本处理成只包含数组 1~5 的形式
$ awk 'gsub(/[^1-5]/,"",$0)' ./nowcoder.txt
12
1
2521# 注意这里的空行
    1. 使用awk按照题目个数输出,其中{ }类似一个循环体,会对文件中的每一行进行迭代
方法三:使用tr删除字符集

tr命令也可以将数据处理成每行只包含1~5数字字符或空行的形式。

cat ./nowcoder.txt | tr -d '/a-z06-9/'  | awk '{print "line"NR" number: "length; total+=length} END{print "sum is "total}'

步骤解析:

tr -d 选项可以删除字符集中的元素,详见如下:

    1. 删除字符集中的所有元素
$ cat ./nowcoder.txt | tr -d '/a-z06-9/'
12
1
2521# 空行
    1. 删除不在字符集的补集中的所有字符
$ cat ./nowcoder.txt | tr -d -c '1-5\n'
12
1
2521# 存在空行
方法四:编写shell脚本函数,类似C语言处理数据
# row=1; sum=0; while read line; do cnt=`echo $line | grep -oE "[1-5]" | wc -l`; echo "line${row} number: ${cnt}"; let "row++"; let "sum+=$cnt"; done < ./nowcoder.txt
row=1          # 记录行数
sum=0          # 记录总字符数
while read line     # 循环读取
do# 使用grep过滤,只输出12345. 使用wc -w 统计字符个数cnt=`echo $line | grep -oE "[1-5]" | wc -l`echo "line${row} number: ${cnt}"let "row++"let "sum+=$cnt"
done < ./nowcoder.txt            # 文件重定向
echo "sum is $sum"

此外,我们也可以将其编写成函数,然后通过脚本调用。

function CountNumber(){local row=1          # 记录行数local sum=0          # 记录总字符数while read line     # 循环读取do# 使用grep过滤,只输出12345. 使用wc -w 统计字符个数cnt=`echo $line | grep -oE "[1-5]" | wc -l`echo "line${row} number: ${cnt}"let "row++"let "sum+=$cnt"done < $1          # 文件重定向return $sum
}# 调用函数
CountNumber $1
echo "sum is $?"      # $? 函数退出返回值

保存为文件,通过 执行shell脚本处理。

14. 求平均值

  • 题目链接:【牛客网 | 求平均值】
  • 题目描述
    写一个bash脚本以实现一个需求,求输入的一个的数组的平均值
    第1行为输入的数组长度N
    第2~N行为数组的元素,如以下为:
    数组长度为4,数组元素为1 2 9 8
    示例:
4
1
2
9
8

那么平均值为:5.000(保留小数点后面3位)
你的脚本获取以上输入应当输出:5.000

方法一:使用awk工具
  1. 在第一行时,记录当前数据,表示数组长度。大于一行时,累加求和。
 awk 'NR==1{cnt=$0} NR>1{sum+=$0} END{printf "%.3f\n" ,sum/cnt}' ./nowcoder.txt
方法二:使用bc命令工具
  1. 将列数据转置成为行数据后,通过字符串拼接成为形如“1+2+3+4…”的形式,再通过bc计算工具计算
sum=`cat ./nowcoder.txt | xargs | cut -d ' ' -f 1 --complement | tr ' ' '+' | bc`
cnt=`cat ./nowcoder.txt | xargs | cut -d ' ' -f 1`
echo "scale=3;"$sum/$cnt | bc

步骤解析:

    1. 列转行
$ cat ./nowcoder.txt | xargs
4 1 2 9 8
    1. 分别取第一列和其余列的数据
# 取第一列的数据
$ cat ./nowcoder.txt | xargs | cut -d ' ' -f 1
4
# 取其余列的数据
$ cat ./nowcoder.txt | xargs | cut -d ' ' -f 1 --complement
1 2 9 8
    1. 拼接字符串,这里使用tr命令将 ‘空格’ 替换为 ‘+’ 。也可以使用sed命令工具
# 使用 tr 替换
$ cat ./nowcoder.txt | xargs | cut -d ' ' -f 1 --complement | tr ' ' '+'
1+2+9+8
# 使用sed 替换
$ cat ./nowcoder.txt | xargs | cut -d ' ' -f 1 --complement | sed 's/ /+/g'
1+2+9+8
    1. 使用 bc计算工具
    • 参数scale=2是将bc输出结果的小数位设置为2位
方法三:通过while循环处理
sum=0            # 累加求和
read cnt         # 读取数组长度
while read num   # 读取剩余部分
dolet "sum+=num"
done
echo "scale=3;$sum/$cnt" | bc

15. 去掉不需要的单词

  • 题目链接:
  • 题目描述
    写一个 bash脚本以实现一个需求,去掉输入中的含有B和b的单词
    示例:
    假设输入如下:
big
nowcoder
Betty
basic
test

你的脚本获取以上输入应当输出:

nowcoder test

说明:
你可以不用在意输出的格式,空格和换行都行

方法一:使用grep文本搜索工具
  1. 使用grep过滤
    -v 过滤掉匹配的行
    -i 忽略大小写
cat ./nowcoder.txt |grep -v -i b
  1. 使用正则匹配
    grep方法过滤掉含有‘B’与‘b’的字符,相关参数如下
    -w --word-regexp # 只显示全字符合的列。
    -x --line-regexp # 只显示全列符合的列。
cat ./nowcoder.txt | grep '[^Bb]*' -x
或
cat ./nowcoder.txt | grep '[^Bb]*' -w
方法二:使用sed流失文本工具
  1. 使用正则匹配 ,参数 ‘d’ 为删除选择的行。
sed /[bB]/d ./nowcoder.txt
  1. 删除‘b’与‘d’所在行
sed '/b/d' ./nowcoder.txt  | sed '/B/d'
# 或
sed '/b/d; /B/d' ./nowcoder.txt
# 或
sed '/B\|b/d' nowcoder.txt
方法三:使用awk工具
  1. 输出不匹配‘B’或‘b’的行
    ~ 匹配正则表达式
    !~ 不匹配正则表达式
awk '$0!~/[B,b]/ {print $0}' ./nowcoder.txt
# 或
awk '$0!~/^B|b/ {print $0}' ./nowcoder.txt

shell 脚本练习 | 「题霸」面试必考真题【shell篇】题解相关推荐

  1. 牛客面试必考真题【算法篇】高频Top200 题目汇总

    题目 出错次数 NC6 二叉树的最大路径和 NC20 数字字符串转化成IP地址 NC21 链表内指定区间反转 NC30 缺失的第一个正整数 NC35 编辑距离(二) 1 NC.38螺旋矩阵 2 NC. ...

  2. 三个不等_2道真题,讲透「基本不等式」的使用原则 | 真题精讲-11

    「不等式」和「最值」之间有着非常天然的强联系:基本不等式有3个非常明显的形式特征:知识点的用法比知识点本身更重要. 先发福利:这里有6场「高考数学」系列Live的讲义,全拿去,送给你--<高考数 ...

  3. 蚂蚁金服面试题泄露,看完这十道面试必问真题,稳拿Offer

    最近编程讨论群有位小伙伴去蚂蚁金服面试了,以下是面试的真题,跟大家一起来讨论怎么回答. 1. 用到分布式事务嘛?为什么用这种方案,有其他方案嘛? 什么是分布式事务 谈到事务,我们就会想到数据库事务,很 ...

  4. 捡漏!蚂蚁金服面试题泄露,看完这十道面试必问真题,冲刺金九银十,稳拿大厂Offer!!

    前言 最近编程讨论群有位小伙伴去蚂蚁金服面试了,以下是面试的真题,跟大家一起来讨论怎么回答. 1. 用到分布式事务嘛?为什么用这种方案,有其他方案嘛? 什么是分布式事务 谈到事务,我们就会想到数据库事 ...

  5. 牛客面试必考算法题刷题

    文章目录 tips 设计LRU缓存结构 判断链表中是否有环 二分查找 实现二叉树先序.中序.后序遍历 寻找第K大 合并有序链表 求二叉树的层次遍历 括号序列 删除列表的倒数第n个节点 链表中的节点每k ...

  6. 2014年12月份计算机,2014年12月计算机必考真题计算机多媒体技术

    1.下列说法中,不正确的是______. A:电子出版物存储容量大,一张光盘可存储几百本书 B:电子出版物可以集成文本.图形.图像.视频和音频等多媒体信息 C:电子出版物不能长期保存 D:电子出版物检 ...

  7. c语言必考100题解析,C语言必考100题

    本文档中包含C语言中绝大部分内容,对于初学C语言的人来说,不得不说是一份特好的资料. 1. 按下述格式,从键盘输入一个整数加法表达式:操作数1+操作数2,然后计算 并输出表达式的计算结果,形式如下:操 ...

  8. 牛客题霸 [数组中未出现的最小正整数] C++题解/答案

    牛客题霸 [数组中未出现的最小正整数] C++题解/答案 题目描述 给定一个无序数组arr,找到数组中未出现的最小正整数 例如arr = [-1, 2, 3, 4].返回1 arr = [1, 2, ...

  9. 牛客题霸 [没有重复项数字的所有排列] C++题解/答案

    牛客题霸 [没有重复项数字的所有排列] C++题解/答案 题目描述 给出一组数字,返回该组数字的所有排列 例如: [1,2,3]的所有排列如下 [1,2,3],[1,3,2],[2,1,3],[2,3 ...

最新文章

  1. html 资源缓存,解决index.html缓存问题
  2. JS中获取焦点和选中的元素
  3. 使用Eclipse trace Application的启动
  4. java ehcahce刷新_Spring整合ehcache 注解实现查询缓存,并实现实时缓存更新或删除...
  5. lengthOfLongestSubstring
  6. tcp选项部分编码_学习编码中最难的部分也是最有趣的部分
  7. 三维重建 几何方法 深度学习_基于深度学习的三维重建算法:MVSNet、RMVSNet、PointMVSNet、Cascade系列...
  8. Web Service学习总结
  9. eclipse ssh mysql_Eclipse 配置SSH 详解
  10. python print 3位小数_python 这样 print 才够骚啊 (3)
  11. [zz]Win8应用商店管理小工具
  12. 在SQL Server 语句中,如何将参数做为表名传递到查询语句中
  13. android uboot boot 区别,uboot fastboot原理
  14. 利用Aria2和Pandown实现科学下载百度云资源
  15. php红包互助源码_完整的微信红包接口API实现(php版)
  16. Remote end closed connection without response
  17. 计算一个整数,转换成二进制,里面有多少个1
  18. Ruby erb模板文件生成html网页的示例
  19. Cesium使用独显GPU提高性能(适用于webGL)
  20. winform直接控制云台_智云和快手发布重磅功能,手机云台升级,帮8成网民拍大片...

热门文章

  1. 从五星酒店到大众浴室——死多头的困境
  2. 2910: 独木桥(bridge)
  3. 南京:平安夜地铁1、2、3号线延时至次日两点
  4. photo-sphere-viewer
  5. 网站太多太杂很烦人?macz小编告诉你如何在Chrome上屏蔽任何网站
  6. 双色球彩票系统(java)
  7. DAY6:利用 PHP 编写登陆页面
  8. KKT条件(卡罗需-库恩-塔克条件)
  9. 频繁默认网关不可用_win10系统默认网关不可用频繁掉线的具体方法
  10. MATLAB字库字库,迪文HMI标准字库及部分扩展字库参考