shell编程练习(一)
1
给定一个文本文件 file.txt,请只打印这个文件中的第十行。
示例:
假设 file.txt 有如下内容:
Line 1 |
你的脚本应当显示第十行:
Line 10 |
解:
sed -n '10p' file.txt |
-n 指除了第十行都不打印
awk 'NR == 10' file.txt |
NR 是 awk 内置的一个变量,表示当前处理的行号(行号从1开始)。这个模式表示如果当前行号等于10,则匹配成功。
tail -n +10 file.txt | head -1 |
tail -n +10 从文件的第十行开始打印,head -1 从头开始打印一行
2
给定一个包含电话号码列表(一行一个电话号码)的文本文件 file.txt,写一个单行 bash 脚本输出所有有效的电话号码。
你可以假设一个有效的电话号码必须满足以下两种格式: (xxx) xxx-xxxx 或 xxx-xxx-xxxx。(x 表示一个数字)
你也可以假设每行前后没有多余的空格字符。
示例:
假设 file.txt 内容如下:
987-123-4567 |
你的脚本应当输出下列有效的电话号码:
987-123-4567 |
解:
grep -E '^(\([0-9]{3}\) |[0-9]{3}-)[0-9]{3}-[0-9]{4}$' file.txt |
-E 启用正则表达式
^: 匹配行的开始。\(: 匹配左括号(。[0-9]{3}: 匹配三个数字。\)或者 ``: 匹配右括号)或者空格。| 表示或者
(\([0-9]{3}\) |[0-9]{3}-)
[0-9]{3}: 匹配三个数字。-: 匹配短横线-。[0-9]{4}: 匹配四个数字。$: 匹配行的结尾。
3
给定一个文件 file.txt,转置它的内容。
你可以假设每行列数相同,并且每个字段由 ' ' 分隔。
示例:
假设 file.txt 文件内容如下:
name age |
应当输出:
name alice ryan |
解:
columns=$(cat file.txt | head -n 1 | wc -w) |
wc -w 统计单词数
$(seq 1 $columns) 表示循环列数,seq用于生成1-seq的数字,seq 1表示生成数字1
awk ‘{print $’$i’}’ 是一个动态引用,print $i 表示打印每行的第几个字段
xargs 逐列将每列转换为行。但是这里我们只需要每次取一列所以需要前置处理
4
写一个 bash 脚本以统计一个文本文件 words.txt 中每个单词出现的
频率
为了简单起见,你可以假设:
words.txt只包括小写字母和' '。- 每个单词只由小写字母组成。
- 单词间由一个或多个空格字符分隔。
示例:
假设 words.txt 内容如下:
the day is sunny the the |
你的脚本应当输出(以词频降序排列):
the 4 |
说明:
- 不要担心词频相同的单词的排序问题,每个单词出现的频率都是唯一的。
- 你可以使用一行 Unix pipes 实现吗?
解:
awk '{for(i=1; i<=NF; i++) {count[$i]++;}} END {for(word in count) {print word, count[word];}}' words.txt | sort -k2,2nr |
awk可以逐行读取每行的单词,NF表示每行的字段数,以单词($i)作为索引来建立计数数组
sort -k2,2nr 对输入进行排序。具体参数含义如下:
-k2,2nr表示按照第二列(单词出现的次数)进行逆序排序。2,2表示从第二列到第二列-n表示按照数值大小排序。-r表示逆序排序。
cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -r | awk '{ print $2, $1 }' |
tr -s ' ' '\n':tr命令用于字符替换,-s ' '表示将多个连续的空格字符替换成一个空格,'\n'表示将空格替换成换行符,因此这一步将文本中的空格分隔的单词转换成每行一个单词的形式。sort:对单词进行排序。uniq -c:uniq命令用于去除连续重复的行,-c选项会显示每行重复出现的次数。因此,这一步会统计每个单词出现的次数。sort -r:对统计结果按照出现次数进行逆序排序。
