准备校招:Linux 文件数据操作练习题熟悉一下吧

举报
山河已无恙 发表于 2022/03/08 11:31:29 2022/03/08
【摘要】 我也不知道为啥这么失落…,只是这终究是要面临的,希望一切都好起来…2021.04.24 统计某个文件的词频[root@liruilong ~]# cat words.txt | xargs -n 1 echo | sort |uniq -c | sort -n -r | awk '{print $2,$1}'the 4is 3sunny 2day 1[root@liruilong ~]# c...

我也不知道为啥这么失落…,只是这终究是要面临的,希望一切都好起来…2021.04.24

统计某个文件的词频

在这里插入图片描述

[root@liruilong ~]# cat words.txt | xargs -n 1 echo | sort |uniq -c | sort -n -r | awk '{print $2,$1}'
the 4
is 3
sunny 2
day 1

[root@liruilong ~]# cat words.txt
the day is sunny the the
the sunny is is
[root@liruilong ~]# 

命令解析

# xarhs -n 1 每个单词逐行显示
# uniq -c 去重并且输入记录次数
# sort -n 排序  -r相反的顺序进行排序
# 分析文本内容 分别输出文本中的第二项 第一项内容
$ cat words.txt | xargs -n 1 echo | sort |uniq -c | sort -n -r | awk '{print $2,$1}'

xargs 命令

xargs命令的作用:是将标准输入转为命令行参数。记忆方法 x + args 将未知数据转化为参数
[root@liruilong ~]# echo "hello world" | xargs echo
hello world
[root@liruilong ~]# 

上面的代码将管道左侧的标准输入,转为命令行参数hello world,传给第二个echo命令。xargs命令的格式如下:

xargs [-options] [command]

真正需要执行的命令,紧跟在xargs后面,接受xargs传来的参数
xargs的作用在于,大多数命令(比如rm、mkdir、ls)与管道一起使用时,都需要xargs将标准输入转为命令行参数。

$ echo "one two three" | xargs mkdir
#上面的代码等同于mkdir one two three。如果不加xargs就会报错,提示mkdir缺少操作参数。
xargs 的单独使用,xargs后面的命令默认是echo
$ xargs
# 等同于
$ xargs echo
#大多数时候,xargs命令都是跟管道一起使用的。但是,它也可以单独使用。

输入xargs按下回车以后,命令行就会等待用户输入,作为标准输入。你可以输入任意内容,然后按下Ctrl d,表示输入结束,这时echo命令就会把前面的输入打印出来。

$ xargs
hello (Ctrl + d)
hello
[root@liruilong ~]# ls
demo     dfg.sh     redis-5.0.7         repodemo.repo  test    words.txt
demo.py  nohup.out  redis-5.0.7.tar.gz  sdf.sh         wer.py
[root@liruilong ~]# xargs find -name
"*.py"
./wer.py
./demo.py
./redis-5.0.7/deps/jemalloc/scripts/gen_travis.py
./redis-5.0.7/deps/jemalloc/scripts/gen_run_tests.py
[root@liruilong ~]# 

上面的例子输入xargs find -name以后,命令行会等待用户输入所要搜索的文件。用户输入"*.py",表示搜索当前目录下的所有 py文件,然后按下Ctrl+d,表示输入结束。这时就相当执行find -name *.py

-d 参数与分隔符

默认情况下,xargs将换行符和空格作为分隔符,把标准输入分解成一个个命令行参数

$ echo "one two three" | xargs mkdir

上面代码中,mkdir会新建三个子目录,因为xargs将one two three分解成三个命令行参数,执行mkdir one two three。-d参数可以更改分隔符。

$ echo -e "a\tb\tc" | xargs -d "\t" echo
a b c

上面的命令指定制表符\t作为分隔符,所以a\tb\tc就转换成了三个命令行参数。echo命令的-e参数表示解释转义字符

-p 参数,-t 参数

使用xargs命令以后,由于存在转换参数过程,有时需要确认一下到底执行的是什么命令。

  • -p参数打印出要执行的命令,询问用户是否要执行。
  • -t参数则是打印出最终要执行的命令,然后直接执行,不需要用户确认。
$ echo 'one two three' | xargs -p touch
touch one two three ?...
$ echo 'one two three' | xargs -t rm
rm one two three
-0 参数与 find 命令

由于xargs默认将空格作为分隔符,所以不太适合处理文件名,因为文件名可能包含空格。

  • find命令有一个特别的参数-print0,指定输出的文件列表以null分隔。然后
  • xargs命令的-0参数表示用null当作分隔符。
$ find /path -type f -print0 | xargs -0 rm

上面命令删除/path路径下的所有文件。由于分隔符是null,所以处理包含空格的文件名,也不会报错。

使得xargs特别适合find命令。有些命令(比如rm)一旦参数过多会报错"参数列表过长",而无法执行,==改用xargs就没有这个问题,因为它对每个参数执行一次命令。==

$ find . -name "*.txt" | xargs grep "abc"

上面命令找出所有 TXT 文件以后,对每个文件搜索一次是否包含字符串abc。

-L 参数

如果标准输入包含多行,-L参数指定多少行作为一个命令行参数。

$ xargs find -name
"*.txt"   
"*.md"
find: paths must precede expression: `*.md'
##上面命令同时将"*.txt"和*.md两行作为命令行参数,传给find命令导致报错。

使用-L参数,指定每行作为一个命令行参数,就不会报错。

$ xargs -L 1 find -name
"*.txt"
./foo.txt
./hello.txt
"*.md"
./README.md
$ echo -e "a\nb\nc" | xargs -L 1 echo
a
b
c
-n 参数

-L参数虽然解决了多行的问题,但是有时用户会在同一行输入多项。-n参数指定每次将多少项,作为命令行参数。

$ xargs find -name
"*.txt" "*.md"
find: paths must precede expression: `*.md`
##上面的命令将同一行的两项作为命令行参数,导致报错。
$ xargs -n 1 find -name
$ echo {0..9} | xargs -n 2 echo
0 1
2 3
4 5
6 7
8 9
-I 参数

如果xargs要将命令行参数传给多个命令,可以使用-I参数
-I指定每一项命令行参数的替代字符串。

$ cat foo.txt
one
two
three

$ cat foo.txt | xargs -I file sh -c 'echo file; mkdir file'
one 
two
three

$ ls 
one two three

上面代码中,foo.txt是一个三行的文本文件。我们希望对每一项命令行参数,执行两个命令(echo和mkdir),使用-I file表示file是命令行参数的替代字符串。执行命令时,具体的参数会替代掉echo file; mkdir file里面的两个file

--max-procs 参数

xargs默认只用一个进程执行命令。如果命令要执行多次,必须等上一次执行完,才能执行下一次。
--max-procs参数指定同时用多少个进程并行执行命令--max-procs 2表示同时最多使用两个进程,--max-procs 0表示不限制进程数。

$ docker ps -q | xargs -n 1 --max-procs 0 docker kill

上面命令表示,同时关闭尽可能多的 Docker 容器,这样运行速度会快很多。

uniq 命令

Linux uniq 命令用于检查及删除文本文件中重复出现的行列,一般与 sort 命令结合使用。uniq 可检查文本文件中重复出现的行列

$ cat testfile      #原有内容  
test 30  
test 30  
test 30  
Hello 95  
Hello 95  
Hello 95  
Hello 95  
Linux 85  
Linux 85 
uniq testfile 
$ uniq testfile     #删除重复行后的内容  
test 30  
Hello 95  
Linux 85 

当重复的行并不相邻时,uniq 命令是不起作用的,即若文件内容为以下时,uniq 命令不起作用:

$ cat testfile1      # 原有内容 
test 30  
Hello 95  
Linux 85 
test 30  
Hello 95  
Linux 85 
test 30  
Hello 95  
Linux 85 
#这时我们就可以使用 sort:
$ sort  testfile1 | uniq
Hello 95  
Linux 85 
test 30
uniq [-cdu][-f<栏位>][-s<字符位置>][-w<字符位置>][--help][--version][输入文件][输出文件]
  • -c或--count 在每列旁边显示该行重复出现的次数。
uniq -c testfile
$ uniq -c testfile      #删除重复行后的内容  
3 test 30             #前面的数字的意义为该行共出现了3次  
4 Hello 95            #前面的数字的意义为该行共出现了4次  
2 Linux 85            #前面的数字的意义为该行共出现了2次  
## 当重复的行并不相邻时统计各行在文件中出现的次数:
$ sort testfile1 | uniq -c
   3 Hello 95  
   3 Linux 85 
   3 test 30
##可以按照每一行的出现次数进行排序,然后显示 
$ sort ostechnix.txt | uniq -c | sort -nr 
  • -d或--repeated 仅显示重复出现的行列。请注意 -d(小写 d) 将会只打印重复的行,每组显示一个。打印所有重复的行,使用 -D(大写 D)
$ sort testfile1 | uniq -d
Hello 95  
Linux 85 
test 30  
  • -f<栏位>或--skip-fields=<栏位> 忽略比较指定的栏位。

为了忽略比较前 N 个字段(LCTT 译注:即前几列)而不是字符,在上面的命令中使用 -f 选项。

  • -s<字符位置>或--skip-chars=<字符位置> 忽略比较指定的字符。
#像对文件中行的前 N 个字符进行限制比较一样,我们也可以使用 -s 选项来忽略比较前 N 个字符。
uniq -d -s 4 ostechnix.txt
  • -u或--unique 仅显示出一次的行列。
  • -w<字符位置>或--check-chars=<字符位置>指定要比较的字符。
#使用 -w 选项来限制对文件中特定数量字符的比较。例如,让我们比较文件中的前四个字符,并显示重复行,如下所示:
uniq -d -w 4 ostechnix.txt
  • --help 显示帮助。
  • --version 显示版本信息。
  • [输入文件] 指定已排序好的文本文件。如果不指定此项,则从标准读取数据;
  • [输出文件] 指定输出的文件。如果不指定此选项,则将内容显示到标准输出设备(显示终端)。

awk 命令

AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。

awk [选项参数] 'script' var=value file(s)awk [选项参数] -f scriptfile var=value file(s)
参数 描述
-F fs or --field-separator fs 指定输入文件折分隔符,fs是一个字符串或者是一个正则表达式,如-F :
-v var=value or --asign var=value 赋值一个用户定义变量。
-f scripfile or --file scriptfile 从脚本文件中读取awk命令。
-mf nnn and -mr nnn 对nnn值设置内在限制,-mf选项限制分配给nnn的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
-W compact or --compat, -W traditional or --traditional 在兼容模式下运行awk。所以gawk的行为和标准的awk完全一样,所有的awk扩展都被忽略。
-W copyleft or --copyleft, -W copyright or --copyright 打印简短的版权信息。
-W help or --help, -W usage or --usage 打印全部awk选项和每个选项的简短说明。
-W lint or --lint 打印不能向传统unix平台移植的结构的警告。
-W lint-old or --lint-old 打印关于不能向传统unix平台移植的结构的警告。
-W posix 打开兼容模式。但有以下限制,不识别:/x、函数关键字、func、换码序列以及当fs是一个空格时,将新行作为一个域分隔符;操作符=不能代替^和^=;fflush无效。
-W re-interval or --re-inerval 允许间隔正则表达式的使用,参考(grep中的Posix字符类),如括号表达式[[:alpha:]]。
-W source program-text or --source program-text 使用program-text作为源代码,可与-f命令混用。
-W version or --version 打印bug报告信息的版本。
awk '{[pattern] action}' {filenames} # 行匹配语句 awk '' 只能用单引号
[root@liruilong ~]# awk '{print $1,$2}' log.txt
2 s
3 Are
This's a
10 There
[root@liruilong ~]# cat log.txt
2 s is a test
3 Are you like awk
This's a test
10 There are orange,apple,mongo
[root@liruilong ~]# awk '{printf "%-8s %-10s\n",$1,$4}' log.txt
2        a         
3        like      
This's             
10       orange,apple,mongo
[root@liruilong ~]# 

awk -F #-F相当于内置变量FS, 指定分割字符
#使用","分割
[root@liruilong ~]#  awk -F, '{print $1,$2}'   log.txt
2 s is a test 
3 Are you like awk 
This's a test '
10 There are orange apple
 # 或者使用内建变量
[root@liruilong ~]# awk 'BEGIN{FS=","} {print $1,$2}'     log.txt
2 s is a test 
3 Are you like awk 
This's a test '
10 There are orange apple
#使用多个分隔符.先使用空格分割,然后对分割结果再使用","分割
[root@liruilong ~]# awk -F '[ ,]'  '{print $1,$2,$5}'   log.txt
2 s test
3 Are awk
This's a 
10 There apple
[root@liruilong ~]# 

awk -v # 设置变量

[root@liruilong ~]# awk -va=1 '{print $1,$1+a}' log.txt
2 3
3 4
This s 1
10 11
[root@liruilong ~]# cat log.txt 
2 s is a test
3 Are you like awk
This s a test
10 There are orange,apple,mongo
[root@liruilong ~]# 
awk -f {awk脚本} {文件名}
$ awk -f cal.awk log.txt
运算符 描述
= += -= *= /= %= ^= **= 赋值
?: C条件表达式
|| 逻辑或
&& 逻辑与
~ 和 !~ 匹配正则表达式和不匹配正则表达式
< <= > >= != == 关系运算符
空格 连接
+ - 加,减
* / % 乘,除与求余
+ - ! 一元加,减和逻辑非
^ *** 求幂
++ – 增加或减少,作为前缀或后缀
$ 字段引用
in 数组成员
过滤第一列大于2的行
[root@liruilong ~]# cat log.txt 
2 s is a test
3 Are you like awk
This's a test
10 There are orange,apple,mongo
[root@liruilong ~]# 
[root@liruilong ~]# 
[root@liruilong ~]# awk '$1>2' log.txt
3 Are you like awk
This's a test
10 There are orange,apple,mongo
过滤第一列等于2的行
[root@liruilong ~]# awk '$1==2 {print $1,$3}' log.txt
2 is
过滤第一列大于2并且第二列等于'Are'的行
[root@liruilong ~]# awk '$1>2 && $2=="Are" {print $1,$2,$3}' log.txt
3 Are you
[root@liruilong ~]# 
内建变量
变量 描述
变量 描述
$n 当前记录的第n个字段,字段间由FS分隔
$0 完整的输入记录
ARGC 命令行参数的数目
ARGIND 命令行中当前文件的位置(从0开始算)
ARGV 包含命令行参数的数组
CONVFMT 数字转换格式(默认值为%.6g)ENVIRON环境变量关联数组
ERRNO 最后一个系统错误的描述
FIELDWIDTHS 字段宽度列表(用空格键分隔)
FILENAME 当前文件名
FNR 各文件分别计数的行号
FS 字段分隔符(默认是任何空格)
IGNORECASE 如果为真,则进行忽略大小写的匹配
NF 一条记录的字段的数目
NR 已经读出的记录数,就是行号,从1开始
OFMT 数字的输出格式(默认值是%.6g)
OFS 输出字段分隔符,默认值与输入字段分隔符一致。
ORS 输出记录分隔符(默认值是一个换行符)
RLENGTH 由match函数所匹配的字符串的长度
RS 记录分隔符(默认是一个换行符)
RSTART 由match函数所匹配的字符串的第一个位置
SUBSEP 数组下标分隔符(默认值是/034)
[root@liruilong ~]#  awk 'BEGIN{printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n","FILENAME","ARGC","FNR","FS","NF","NR","OFS","ORS","RS";printf "---------------------------------------------\n"} {printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n",FILENAME,ARGC,FNR,FS,NF,NR,OFS,ORS,RS}'  log.txt
FILENAME ARGC  FNR   FS   NF   NR  OFS  ORS   RS
---------------------------------------------
log.txt    2    1         5    1         
log.txt    2    2         5    2         
log.txt    2    3         3    3         
log.txt    2    4         4    4         
[root@liruilong ~]# awk -F\' 'BEGIN{printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n","FILENAME","ARGC","FNR","FS","NF","NR","OFS","ORS","RS";printf "---------------------------------------------\n"} {printf "%4s %4s %4s %4s %4s %4s %4s %4s %4s\n",FILENAME,ARGC,FNR,FS,NF,NR,OFS,ORS,RS}'  log.txt
FILENAME ARGC  FNR   FS   NF   NR  OFS  ORS   RS
---------------------------------------------
log.txt    2    1    '    1    1         
log.txt    2    2    '    1    2         
log.txt    2    3    '    2    3         
log.txt    2    4    '    1    4         
[root@liruilong ~]# awk '{print NR,FNR,$1,$2,$3}' log.txt
# 输出顺序号 NR, 匹配文本行号
1 1 2 s is
2 2 3 Are you
3 3 This s a test
4 4 10 There are
[root@liruilong ~]# awk '{print $1,$2,$5}' OFS=" $ "  log.txt
# 指定输出分割符
2 $ s $ test
3 $ Are $ awk
This's $ a $ 
10 $ There $ 
[root@liruilong ~]# 
使用正则,字符串匹配
[root@liruilong ~]# cat log.txt 
2 s is a test
3 Are you like awk
This s a test
10 There are orange,apple,mongo
[root@liruilong ~]# awk '$2 ~ /Th/' log.txt
10 There are orange,apple,mongo
[root@liruilong ~]# awk '$2 ~ /Th/ {print $2,$4}' log.txt
There orange,apple,mongo
[root@liruilong ~]# 

~ 表示模式开始。// 中是模式。

[root@liruilong ~]# awk '/yo/ ' log.txt 
3 Are you like awk
[root@liruilong ~]# 
忽略大小写
[root@liruilong ~]# awk 'BEGIN{IGNORECASE=1} /this/' log.txt
This's a test
[root@liruilong ~]# cat log.txt 
2 s is a test
3 Are you like awk
This's a test
10 There are orange,apple,mongo
[root@liruilong ~]# 
模式取反
[root@liruilong ~]# awk '$2 !~ /th/ {print $2,$4}' log.txt
s a
Are like
a 
There orange,apple,mongo
[root@liruilong ~]# cat log.txt 
2 s is a test
3 Are you like awk
This's a test
10 There are orange,apple,mongo
[root@liruilong ~]# awk '!/th/ {print $2,$4}' log.txt
s a
Are like
a 
There orange,apple,mongo
[root@liruilong ~]# 
awk脚本

关于 awk 脚本,我们需要注意两个关键词BEGINEND

  • BEGIN{ 这里面放的是执行前的语句 }
  • END {这里面放的是处理完所有的行后要执行的语句 }
  • {这里面放的是处理每一行时要执行的语句}
    假设有这么一个文件(学生成绩表):
[root@liruilong ~]# cat score.txt
Marry   2143 78 84 77
Jack    2321 66 78 45
Tom     2122 48 77 71
Mike    2537 87 97 95
Bob     2415 40 57 62
[root@liruilong ~]# 
#!/bin/awk -f
#运行前
BGEIN {
    math = 0
    english = 0
    computer = 0

    printf "NAME    NO.   MATH  ENGLISH  COMPUTER   TOTAL\n"
    printf "---------------------------------------------\n"
}
#运行中
{
    math+=$3
    english+=$4
    computer+=$5
    printf "%-6s %-6s %4d %8d %8d %8d\n", $1, $2, $3,$4,$5, $3+$4+$5
}
#运行后
END {
    printf "---------------------------------------------\n"
    printf "  TOTAL:%10d %8d %8d \n", math, english, computer
    printf "AVERAGE:%10.2f %8.2f %8.2f\n", math/NR, english/NR, computer/NR
}
~           
[root@liruilong ~]# awk -f cal.awk score.txt
Marry  2143     78       84       77      239
Jack   2321     66       78       45      189
Tom    2122     48       77       71      196
Mike   2537     87       97       95      279
Bob    2415     40       57       62      159
---------------------------------------------
  TOTAL:       319      393      350 
AVERAGE:     63.80    78.60    70.00
[root@liruilong ~]# awk 'BEGIN { print "Hello, world!" }' 
Hello, world!
[root@liruilong ~]# awk 'length>80' log.txt
[root@liruilong ~]# 
[root@liruilong ~]# seq 9 | sed 'H;g' | awk -v RS='' '{for(i=1;i<=NF;i++)printf("%dx%d=%d%s", i, NR, i*NR, i==NR?"\n":"\t")}'
1x1=1
1x2=2	2x2=4
1x3=3	2x3=6	3x3=9
1x4=4	2x4=8	3x4=12	4x4=16
1x5=5	2x5=10	3x5=15	4x5=20	5x5=25
1x6=6	2x6=12	3x6=18	4x6=24	5x6=30	6x6=36
1x7=7	2x7=14	3x7=21	4x7=28	5x7=35	6x7=42	7x7=49
1x8=8	2x8=16	3x8=24	4x8=32	5x8=40	6x8=48	7x8=56	8x8=64
1x9=9	2x9=18	3x9=27	4x9=36	5x9=45	6x9=54	7x9=63	8x9=72	9x9=81
[root@liruilong ~]# 

转置文件

在这里插入图片描述
解法一:

# NR已经读出的记录数,就是行号,从1开始
# NF一条记录的字段的数目

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 

解法二:
解题思路为一列一列的读取文本,再使用xargs命令将列平铺开,达到转置的效果。其中读取列可以使用cut命令或awk命令。

COUNT=`head -1 file.txt | wc -w`
for (( i = 1; i <= $COUNT; i++ ));do
awk -v arg=$i '{print $arg}' file.txt | xargs
done

有效电话号码

在这里插入图片描述

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

第十行

在这里插入图片描述

[root@liruilong ~]# sed -n '10p' file.txt 
Line 10
[root@liruilong ~]# awk 'NR==10' file.txt 
Line 10
[root@liruilong ~]# cat file.txt
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
Line 9
Line 10
[root@liruilong ~]# 

sed 命令

Linux sed 命令是利用脚本来处理文本文件。sed 可依照脚本的指令来处理、编辑文本文件。Sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。