写一个 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
说明:
题解一
cat words.txt | tr -s ' ' '\n' | sort | uniq -c | sort -r | awk '{ print $2, $1 }'
说明
tr 命令用于转换或删除文件中的字符
-s:缩减连续重复的字符成指定的单个字符
sort:排序
uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。
-c:在每列旁边显示该行重复出现的次数。
-r:以相反的顺序来排序 就是反一下一行的数据
awk '{print $2, $1}' 打印把第一列和第二列数字反一下
题解二
cat words.txt | xargs -n 1 | sort | uniq -c | sort -nr | awk '{print $2" "$1}'
说明
xargs -n1 使用 xargs 将所有行转为单列显示
sort -nr 表示依照数值的大小降序排序
uniq -c 表示在每列旁边显示该行重复出现的次数
awk + print 函数将 1、2 列位置互换
题解三
cat words.txt |
awk '{
for(i=1;i<=NF;i++){
count[$i]++
}
} END {
for(k in count){
print k" "count[k]
}
}' |
sort -rnk 2
说明
在awk中我们用一个字典(?)count储存每个单词的词频,先遍历每一行(awk自身机制)的每一个字段(i<=NF),然后用该字段本身作为key,将其value++;最后用一个for循环输出count数组中的每个元素的key(词)及其value(词频)。
最后用|管道命令传给sort命令:
-r是倒序排序,相当于DESC
-n是将字符串当作numeric数值排序
-k则指定用于排序的字段位置,后跟2指将第二位的count[k](词频)作为排序的key
题解四 python版本(运行比较慢)
python3 -c "a=open('words.txt').read().split();from collections import Counter;c=list(Counter(a).items());c.sort(key=lambda x:-x[1]);[print(x,y)for x,y in c]"
题解五
# 统计词频率
declare -A F # 键值对数组 记录词与出现频率
for word in `< words.txt`;do # 使用重定向符 <, 而不是 cat 命令
((F[$word]++)) # C风格的增1,这里数组变量名前不能加 $,否则有语法错误
done
# 按频率高低打印
while [[ ${#F[@]} -gt 0 ]];do # 数组元素个数
mx=0 # 出现次数最多词 数
unset wd # 对应上面的 词
for i in ${!F[*]};do # 遍历 数组的 key
[[ ${F[$i]} -gt $mx ]] && { # 比较最大次数词
mx=${F[$i]}
wd="$i"; }
done
[[ $mx -ne 0 ]] && echo $wd $mx # 打印
unset F[$wd] # 删除 已经打印了的词
done
题解六
cat words.txt | xargs -n 1 | awk '{
if($1 in data)
data[$1] = data[$1] + 1
else
data[$1] = 1
} END {for(str in data) print data[str],str}' | sort -rn | awk '{print $2, $1}'
第一步:将文件单词进行每行一个输出(使用xargs命令)(此处可以不用,也可以使用awk脚本NF处理)
第二步:使用awk数组进行统计(数组+MAP概念),并输出
第三步:将输出元素进行倒序排序 + 输出位置调整 (sort+awk
给定一个包含电话号码列表(一行一个电话号码)的文本文件 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
题解一
grep -P '^([0-9]{3}-|\([0-9]{3}\) )[0-9]{3}-[0-9]{4}$' file.txt
题解二
grep -P '^((\(\d{3}\) )|(\d{3}-))\d{3}-\d{4}$' file.txt
说明
-P 使用 Perl 拓展正则,主要是为了支持\d匹配数字
^ 要求匹配的字符串是在行首,防止出现abc123-456-7890这种情况
$ 要求匹配的字符串在行尾,防止出现123-456-7890abc这种情况
\d 匹配数字0-9 等价于[0-9]
{3} 前面的匹配出现三次,就是匹配连续三个数字
(、) 以及中间的| 用来分组,括号内的是一组,这里嵌套了一次括号并用了|(或),为了实现的是(\(\d{3}\) )和(\d{3}-)的二选一
\(、\) 括号转义
题解三 (速度最快!)
sed -rn "/^((\([0-9]{3}\) )|[0-9]{3}-)[0-9]{3}-[0-9]{4}$/p" file.txt
说明
sed -rn 使用Regex+不输出加工过程
^((\([0-9]{3}\) )|[0-9]{3}-) #(开头+3数字+)结尾+空格 或者 3数字+一个连接符
[0-9]{3}-[0-9]{4}$ # 3数字+连接符+4数字+本行结束符
/p 打印匹配
题解四
cat file.txt | grep -P "^(\([0-9]{3}\)\s|[0-9]{3}-)[0-9]{3}-[0-9]{4}$"
题解五 python 运行最慢
python3 -c "import re;lines=open('file.txt').readlines();lines=[i.strip()for i in lines];ans=[i for i in lines if re.match('^\(\d{3}\) \d{3}-\d{4}$',i) or re.match('^\d{3}-\d{3}-\d{4}$',i)]; print('\n'.join(ans))"
给定一个文件 file.txt,转置它的内容。
你可以假设每行列数相同,并且每个字段由 ’ ’ 分隔。
示例:
假设 file.txt 文件内容如下:
name age
alice 21
ryan 30
应当输出:
name alice ryan
age 21 30
题解一
# 获取第一行,然后用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
题解二
columns=$(cat file.txt | head -n 1 | wc -w)
for i in $(seq 1 $columns)
do
awk '{print $'''$i'''}' file.txt | xargs
done
题解三
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
题解四
COUNT=`head -1 file.txt | wc -w`
for (( i = 1; i <= $COUNT; i++ )); do
cut -d' ' -f$i file.txt | xargs
done
题解五
COUNT=`head -1 file.txt | wc -w`
for (( i = 1; i <= $COUNT; i++ )); do
awk -v arg=$i '{print $arg}' file.txt | xargs
done
题解六
#!/bin/bash
line=`cat file.txt|awk '{print NF}'|head -n 1`
for n in $(seq 1 ${line});
do
cat file.txt |awk -v n=$n '{print $n}' |xargs echo
done
给定一个文本文件 file.txt
,请只打印这个文件中的第十行。
示例:
假设 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. 如果文件少于十行,你应当输出什么?
\2. 至少有三种不同的解法,请尝试尽可能多的方法来解题。
题解一
sed -n "10p" file.txt
题解二
tail -n +10 file.txt | head -1
对于行数的提取
awk '{print NR}' file.txt | tail -n1
10
awk 'END{print NR}' file.txt
10
grep -nc "" file.txt
10
grep -c "" file.txt
10
grep -vc "^$" file.txt
10
grep -n "" file.txt|awk -F: '{print '}|tail -n1 | cut -d: -f1
10
grep -nc "" file.txt
10
sed -n "$=" file.txt
10
wc -l file.txt
10 file.txt
cat file.txt | wc -l
10
wc -l file.txt | cut -d' ' -f1
10