[转帖] Linux文本命令技巧(下)
https://www.cnblogs.com/codelogs/p/16060108.html
简介#
前一篇介绍了Linux中一些基本的文本命令与使用技巧,但是结合场景过少,本篇结合工作中一些常见的场景介绍一些技巧。
数据提取#
数据提取在文本处理中是常见,提取单个值可以使用grep -o功能,如下:
# 如下ifconfig的输出,目标是提取inet后面的ip
$ ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.22.82.18  netmask 255.255.240.0  broadcast 172.22.95.255
        inet6 fe80::215:5dff:fec7:b486  prefixlen 64  scopeid 0x20<link>
        ether 00:15:5d:c7:b4:86  txqueuelen 1000  (Ethernet)
        RX packets 130047  bytes 83292033 (83.2 MB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 72272  bytes 7117481 (7.1 MB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING>  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10<host>
        loop  txqueuelen 1000  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
# 通过-o可以仅输出匹配的部分,而不是匹配的行
$ ifconfig|grep -oP 'inet \w+.\w+.\w+.\w+'
inet 172.22.82.18
inet 127.0.0.1
# 通过添加\K,能够指定只输出\K后面的部分,而不是匹配部分
$ ifconfig|grep -oP 'inet \K\w+.\w+.\w+.\w+'
172.22.82.18
127.0.0.1
这样虽然达到了提取单个值的效果,但如果我们需要同时提取ip与netmask呢?仅通过grep就不那么容易实现了,如下:
# \K的效果,并没有只提取ip与netmask
$ ifconfig|grep -oP 'inet \K\w+.\w+.\w+.\w+  netmask \w+.\w+.\w+.\w+'
172.22.82.18  netmask 255.255.240.0
127.0.0.1  netmask 255.0.0.0
# 这里最直接的方法,是使用pcre2grep,它提供了捕获组的功能
$ ifconfig|pcre2grep -O '$1 $2' 'inet (\w+.\w+.\w+.\w+)  netmask (\w+.\w+.\w+.\w+)'
172.22.82.18 255.255.240.0
127.0.0.1 255.0.0.0
# 也可以使用sed、awk来实现
$ ifconfig|sed -nE 's/.*inet (\w+.\w+.\w+.\w+)  netmask (\w+.\w+.\w+.\w+).*/\1 \2/p'
172.22.82.18 255.255.240.0
127.0.0.1 255.0.0.0
$ ifconfig|awk 'match($0,/inet (\w+.\w+.\w+.\w+)/, a) && match($0,/netmask (\w+.\w+.\w+.\w+)/,b){print a[1],b[1]}'
172.22.82.18 255.255.240.0
127.0.0.1 255.0.0.0
# 通过shell的BASH_REMATCH也可以,这种相当于写脚本了,注意:BASH_REMATCH不支持\w,特殊字符需要用\转义
$ ifconfig|while read line;do [[ "$line" =~ inet\ ([0-9]+.[0-9]+.[0-9]+.[0-9]+)\ \ netmask\ ([0-9]+.[0-9]+.[0-9]+.[0-9]+) ]] && echo ${BASH_REMATCH[1]} ${BASH_REMATCH[2]}; done
172.22.82.18 255.255.240.0
127.0.0.1 255.0.0.0
最后一列带分隔符问题#
有些时候,文本的最后一列会包含分隔符,这种情况会使得cut、awk之类的命令处理起来很困难,比如ps -ef的输出:
# ps -f输出中的CMD字段值本身带有空格
$ ps -f
UID        PID  PPID  C STIME TTY          TIME CMD
root      2282  2281  0 Jan21 pts/1    00:00:00 /bin/bash -l -i -c . /mnt/c/Users/root/AppData/Local/Temp/Mxt123/tmp/MOBASC~2.SH;bash -i
root      2295  2282  0 Jan21 pts/1    00:00:04 bash -i
root     18166  2295  0 12:02 pts/1    00:00:00 ps -f
# 直接用awk来提取PID、CMD列,会发现CMD列丢失了一部分
$ ps -f|awk '{print $2,$8}'
PID CMD
2282 /bin/bash
2295 bash
18177 ps
18178 awk
# 办法1,使用split函数,然后定义一个jointon函数,将分拆的CMD列拼接还原
$ ps -ef|awk 'function jointon(f,s,n){for(i=n+1;i<=length(f);i++){f[n]=f[n] s[i-1] f[i]};return 1}
        split($0,f,/\s+/,s) && jointon(f,s,8){print f[2],f[8]}'
PID CMD
2282 /bin/bash -l -i -c . /mnt/c/Users/root/AppData/Local/Temp/Mxt123/tmp/MOBASC~2.SH;bash -i
2295 bash -i
18235 ps -f
# 办法2,将CMD列中的空格替换为特殊字符,之后再替换回来
$ ps -f|sed -E 's/\s+/-_-/8g'|awk '{print $2,$8}'|sed -E 's/-_-/ /g'
PID CMD
2282 /bin/bash -l -i -c . /mnt/c/Users/root/AppData/Local/Temp/Mxt123/tmp/MOBASC~2.SH;bash -i
2295 bash -i
18221 ps -f
# 办法3,从CMD前将一行切成2行,并添加一个空行便于awk按段划分记录
$ ps -f|sed -E 's/\s+/\n/7;a\\n'
UID        PID  PPID  C STIME TTY          TIME
CMD
root      2282  2281  0 Jan21 pts/1    00:00:00
/bin/bash -l -i -c . /mnt/c/Users/root/AppData/Local/Temp/Mxt123/tmp/MOBASC~2.SH;bash -i
root      2295  2282  0 Jan21 pts/1    00:00:04
bash -i
root     18254  2295  0 12:15 pts/1    00:00:00
ps -f
$ ps -f|sed -E 's/\s+/\n/7;a\\n'|awk -F'\n' -v RS='' 'split($1,a,/\s+/){print a[2],$2}'
PID CMD
2282 /bin/bash -l -i -c . /mnt/c/Users/root/AppData/Local/Temp/Mxt123/tmp/MOBASC~2.SH;bash -i
2295 bash -i
18295 ps -f
字符串连接#
将一行一行的数据,用某个字符拼接成一行,这个也非常有用,如下:
# 用paste是最简单的办法
$ seq 9|paste -s -d,
1,2,3,4,5,6,7,8,9
# 用tr将换行符替换为,也可以
$ seq 9|tr '\n' ','
1,2,3,4,5,6,7,8,9,
# xargs配合printf也可以,但注意xargs有时会将"抹掉,这时可加上-d'\n'解决
$ seq 9|xargs printf "%s,"
1,2,3,4,5,6,7,8,9,
# sed将换行符替换为,也可以,不过这里需要使用-z选项将所有行读取进来,不然sed是一行一行处理的
$ seq 9|sed -z 's/\n\b/,/g'
1,2,3,4,5,6,7,8,9
# awk当然也可以
$ seq 9|awk 'NR>1{printf ","}{printf $0}'
1,2,3,4,5,6,7,8,9
$ seq 9|awk -v RS='^$' '{gsub(/\n/, ",", $0);print $0}'
1,2,3,4,5,6,7,8,9,
数据变换#
将数据做简单的变换也是很常用的,什么是变换看看下面的例子就知道了:
# 用sed直接替换
$ seq 5|sed -E 's/.+/{"orderId":"&"}/'
{"orderId":"1"}
{"orderId":"2"}
{"orderId":"3"}
{"orderId":"4"}
{"orderId":"5"}
# 用awk当然也可以
$ seq 5|awk -v f='{"orderId":"%s"}\n' '{printf f,$0}'
{"orderId":"1"}
{"orderId":"2"}
{"orderId":"3"}
{"orderId":"4"}
{"orderId":"5"}
# xargs配合printf也行
$ seq 5|xargs printf '{"orderId":"%s"}\n'
{"orderId":"1"}
{"orderId":"2"}
{"orderId":"3"}
{"orderId":"4"}
{"orderId":"5"}
上面都是单行变换,有时我们还需要分组,比如每3行分一组,如下:
# 分组的话,这里最简单就是用paste
# 每3个一组,就用3个-
$ seq 8|paste -d, - - -
1,2,3
4,5,6
7,8,
# 同样使用paste分组,这里- - -,是用yes加head生成的,不然如果1000个分一组,难道还手写1000个-
$ seq 8|paste -d, $(yes -|head -n3)
1,2,3
4,5,6
7,8,
# 还是paste分组,不过分隔符指定多个,循环使用
$ seq 8|paste -sd "$(yes ,|head -n2|tr -d '\n')\n"
1,2,3
4,5,6
7,8
# 用parallel加paste也很简单,这里parallel将每3行输入到一个paste命令里面去
$ seq 8|parallel --pipe -N3 paste -d, -s
1,2,3
4,5,6
7,8
# xargs配合printf
$ seq 8|xargs -L3 bash -c 'printf "$@" && echo' - '%s,'
1,2,3,
4,5,6,
7,8,
# xargs配合IFS
$ seq 8|xargs -L3 bash -c 'IFS=,; echo "$*"' -
1,2,3
4,5,6
7,8
# sed也可以,用到了sed的分支功能,sed的一种高级用法
# :a表示一个标签,N表示将下一行也读取进来,而ba表示回到这个标签再次执行,所以0~3!{$!ba}表示读3行或读到最后一行
# s/\n/,/g替换换行为逗号,所以每读到的3行文本,就变成了逗号连接的3列
$ seq 8|sed ':a;N;0~3!{$!ba};s/\n/,/g'
1,2,3
4,5,6
7,8
# awk当然也可以
$ seq 8|awk 'NR%3!=1{s=s","$0} NR%3==1{if(s)print s;s=$0} END{print s}'
1,2,3
4,5,6
7,8
然后将上面两种方法一起使用,就可以达到先变换再分组的效果了,如下:
$ seq 8|sed -E 's/.+/{"orderId":"&"}/'|paste -d, $(yes -|head -n3)
{"orderId":"1"},{"orderId":"2"},{"orderId":"3"}
{"orderId":"4"},{"orderId":"5"},{"orderId":"6"}
{"orderId":"7"},{"orderId":"8"},
json数据变换
像这种分隔形式的数据变json,json变分隔形式的数据,使用jq也可以实现,因为jq就是专门处理json数据的啊!
# 比如这种数据
$ cat person.txt
1,zhangsan
2,lisi
3,wangwu
# 用jq将其变换为json,splits可以写正则
$ cat person.txt |jq -R '[splits(",")] as [$f1,$f2]|{id: $f1, name: $f2}' -c
{"id":"1","name":"zhangsan"}
{"id":"2","name":"lisi"}
{"id":"3","name":"wangwu"}
# 当然前面说的变换方法也是可以的(注:结果同时写入到了person.json)
$ cat person.txt |sed -E 's/(\w+),(\w+)/{"id":"\1","name":"\2"}/' |tee person.json
{"id":"1","name":"zhangsan"}
{"id":"2","name":"lisi"}
{"id":"3","name":"wangwu"}
# 将json变换为,分隔形式
$ cat person.json |jq ' "\(.id),\(.name)" ' -r
1,zhangsan
2,lisi
3,wangwu
# 当然,使用前面的数据提取过程也可以实现
$ cat person.json |awk 'match($0,/"id":"(\w+)"/,a) && match($0,/"name":"(\w+)"/,b){print a[1] "," b[1]}'
1,zhangsan
2,lisi
3,wangwu
# 但对于多层级的json,awk也无能为力了,只能使用jq了,如下:
$ cat person.json
{"id":"1","name":"zhangsan","score":[{"yuwen":56},{"shuxue":76}]}
{"id":"2","name":"lisi","score":[{"yuwen":76},{"shuxue":83}]}
{"id":"3","name":"wangwu","score":[{"yuwen":92},{"shuxue":89}]}
$ cat person.json|jq ' "\(.id),\(.name),\([.score[]|values[]]|join(":"))" ' -r
1,zhangsan,56:76
2,lisi,76:83
3,wangwu,92:89
jq本身也是个很强大的命令,具体可以man jq查看。
驼峰转下划线#
驼峰与下划线字段的互转,如下:
# 驼峰转下划线
$ echo "userId"|sed -E 's/([A-Z]+)/_\l\1/g'
user_id
# 下划线转驼峰
$ echo "user_id"|sed -E 's/_(.)/\u\1/g'
userId
超大日志文件搜索#
很多时候我们需要搜索一小段时间范围内日志,比如查看这段时间内是否有异常产生,从而导致某些接口超时,用grep、sed、awk命令都很容易处理这类事情。
比如只关注2021-01-22 15:00:10到2021-01-22 15:03:10的日志。
# grep通过正则可以实现范围型的过滤,但写起来有点费劲
grep -E '2021-01-22 15:(00:(1[0-9]|[2-9][0-9])|0[12]:[0-9][0-9]|03:(0[0-9]|10))' app.log
# sed、awk本身支持范围型查找,但必须日志中包含这两个日期
sed -n '/2021-01-22 15:00:10/,/2021-01-22 15:03:10/ p'
# awk改造一下,这样完善一些,在awk那篇介绍过
cat app.log|awk 'match($0,/^([0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2})/,a){if(a[1]>="2021-01-22 15:00:10")print $0; if(a[1]>"2021-01-22 15:03:10")exit}'
但如果日志文件大小超过10G,上面那些方法都会执行得很慢,因为它们会将整个文件的内容都遍历一遍。
但其实我们只需要一小段时间范围的日志,可不可以只读取日志文件中那一小段范围的内容呢?
通过dd命令是可以的,dd命令可以做到从文件指定的偏移量开始读取,利用这个特性,可以写个脚本实现快速读取指定时间范围日志,如下:
- 先读开始位置第一行,看看时间是多少,并记下文件偏移量。
- 再读100M位置后的第一行,看看时间是多少,并记下文件偏移量。
- 再读200M位置后的第一行,看看时间是多少,并记下文件偏移量。
- 一直循环下去,直到文件结束。
- 然后看看我们需要的时间范围,在哪个100M内,使用dd从那个偏移量开始读100M,再通过上面介绍的grep、sed、awk过滤即可。
function every100m(){
    let i=0;
    let l=$(du -b $1|cut -f1);
    while [[ $i -lt $l ]];do
        time=$(dd if=$1 iflag=skip_bytes,count_bytes skip=$i count=10K 2>/dev/null|grep -m1 -oP '\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}');
        printf "%12s\t%s\n" $i "$time"
        let i=i+104857600
    done
}
# 这是一个510M的日志文件
$ every100m app.log
           0    2021-01-22 11:43:39
   104857600    2021-01-22 14:00:52
   209715200    2021-01-22 16:00:04
   314572800    2021-01-22 18:00:10
   419430400    2021-01-22 20:33:52
   524288000    2021-01-22 23:30:10
# 可以发现2021-01-22 15:00:10到2021-01-22 15:03:10的日志,都在104857600这个偏移量后的100M内
# 统计了一下,这个时间段有8587条日志,几乎秒出
$ dd if=app.log iflag=skip_bytes,count_bytes skip=104857600 count=100M 2>/dev/null|sed -n '/2021-01-22 15:00:10/,/2021-01-22 15:03:10/ p'|wc -l
8587
大文件拆分#
split命令,用于将一个大文件拆分为多个小文件,如下:
将2.7G的日志,按一个500M大小,拆分为多个文件
$ ll
total 2.7G
-rw-r--r-- 1 work work 2.7G 2022-12-03 15:23:51 app.log
# 拆分文件,-b指定拆分大小,split_applog_表示拆分文件名的前缀
$ split -b 500m app.log split_applog_
$ ll
total 5.3G
-rw-r--r-- 1 work work 2.7G 2022-12-03 15:23:51 app.log
-rw-r--r-- 1 work work 500M 2022-12-03 15:29:28 split_applog_aa
-rw-r--r-- 1 work work 500M 2022-12-03 15:29:29 split_applog_ab
-rw-r--r-- 1 work work 500M 2022-12-03 15:29:30 split_applog_ac
-rw-r--r-- 1 work work 500M 2022-12-03 15:29:32 split_applog_ad
-rw-r--r-- 1 work work 500M 2022-12-03 15:29:33 split_applog_ae
-rw-r--r-- 1 work work 191M 2022-12-03 15:29:35 split_applog_af
对于日志文件拆分,一般不希望将整行拆分到不同文件中,这时可以使用-l选项,如下:
# 每30w行拆一个日志文件
$ split -l 30000 app.log split_applog_
# 使用csplit也可以
$ csplit -k app.log 300000 {*} -f split_applog_
标准输出拆分
在启动程序时,我们经常会需要将标准输出与标准错误重定向到一个日志文件中,如下:
java -jar app.jar > app_stdout.log
但由于这种后台程序,运行时间可能非常长,因此app_stdout.log有可能会变得非常大,我们想每小时保存一个日志文件,怎么办呢?
- 按行数拆分
 可以使用split来实现,如下:
java -jar app.jar > >(split -l 300000 - app_stdout_ --additional-suffix=.log)
这里用到了bash的进程替换语法>(command),重定向的标准输出日志,会被split写到拆分的文件中,若想按大小拆分的话,使用split -b即可。
- 按时间拆分
 比如每小时一个文件,可以使用timeout和cat命令实现,如下:
java -jar app.jar > >(while ((++n));do timeout 1h cat > app_stdout_$(date +%F-%H)_$n.log;[[ $? -ne 124 ]] && break;done)
重定向的标准输出日志,会被cat写到拆分的日志文件中,但timeout让cat每次只写1个小时。
csvkit#
对于csv文件的分析,可以使用csvkit这个软件包,基于python实现的,提供了很多实用的功能,不多说,体会一下:
# 安装csvkit
$ sudo pip install csvkit
# 将excel文件变成csv
$ in2csv data.xls > data.csv
# 将json文件变成csv
$ in2csv data.json > data.csv
# 将csv文件变成json
$ csvjson -y0 -I data.csv > data.json
# csv分隔符变成tab键,然后给awk处理,因为字段值本身太容易包含逗号了
$ csvformat data.csv -T|awk -F $'\t' 'NR>1{print $3}'
# mysql命令查询内容导出为csv
$ mysql -e 'select * from user'|csvformat -t > user.csv
# 直接使用SQL分析csv中的数据,这真是太实用了
$ csvsql -y0 -I --query "select a.id,a.name,b.age from name a join age b on a.id=b.id" name.csv age.csv| csvlook | less -S
pup#
对于html类型的数据,可以使用pup这个命令来解析提取,有了这个命令,就可以用脚本来实现简单的爬虫了,如下:
# 安装pup,go开发的
$ go get github.com/ericchiang/pup
# 获取title标签的文本内容,使用的是css selector语法,详细可以去github看下
$ curl -s www.baidu.com|pup 'title text{}'
百度一下,你就知道
# 获取所有body标签下所有a标签的链接属性值
$ curl -s www.baidu.com|pup 'body a attr{href}'
http://news.baidu.com
http://www.hao123.com
http://map.baidu.com
http://v.baidu.com
http://tieba.baidu.com
# 同样的,返回json格式的数据
$ curl -s www.baidu.com|pup 'body a json{}'
[
 {
  "class": "mnav",
  "href": "http://news.baidu.com",
  "name": "tj_trnews",
  "tag": "a",
  "text": "新闻"
 },
 {
  "class": "mnav",
  "href": "http://www.hao123.com",
  "name": "tj_trhao123",
  "tag": "a",
  "text": "hao123"
 }
]
总结#
上面这些Linux文本处理技巧,都是我在工作过程中,琢磨好久一个个想出来的,而且它们的实现思路和普通编程思路很不一样,所以学习这些命令对于扩展编程思路也会有帮助。
如果你也对这些命令非常感兴趣,一定要亲自试试这些命令,并将它们用于实际工作场景中。
往期内容#
Linux文本命令技巧(上)
原来awk真是神器啊
提高工作效率,jq命令来帮你
不容易自己琢磨出来的正则表达式用法
好用的parallel命令
常用网络命令总结
[转帖] Linux文本命令技巧(下)的更多相关文章
- linux常用命令技巧
		原文地址 这篇文章来源于Quroa的一个问答<What are some time-saving tips that every Linux user should know?>—— Li ... 
- [转帖]linux sed命令
		linux sed命令就是这么简单 https://www.cnblogs.com/wangqiguo/p/6718512.html 用到的最多的就是一个sed -i 's/nn/mm/' 的命令了. ... 
- [转帖]Linux Shell常用技巧(五)
		Linux Shell常用技巧(五) https://zhuanlan.zhihu.com/p/73451771 1. 变量:在awk中变量无须定义即可使用,变量在赋值时即已经完成了定义.变量的类型可 ... 
- [转帖]linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习)
		linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习) https://www.cnblogs.com/caozy/p/9261224.html 总结的挺好的 ... 
- [转帖]linux screen 命令详解,xshell关掉窗口或者断开连接,查看断开前执行的命令
		linux screen 命令详解,xshell关掉窗口或者断开连接,查看断开前执行的命令 https://binwaer.com/post/12.html yun install -y screen ... 
- [转帖]linux tree命令--显示目录的树形结构
		linux tree命令--显示目录的树形结构 版权声明:iamqilei@qq.com https://blog.csdn.net/u011729865/article/details/533 ... 
- [转帖]Linux date命令的用法(转)
		Linux date命令的用法(转) https://www.cnblogs.com/asxe/p/9317811.html 1.命令:date 2.命令功能:date 可以用来显示或设定系统的日期与 ... 
- [转帖]Linux chattr 命令详解
		Linux chattr 命令详解 https://www.cnblogs.com/ftl1012/p/chattr.html 常见命令参数 1 2 3 4 5 6 7 8 9 10 11 12 A: ... 
- 在Linux终端命令行下播放音乐的命令(Ubuntu)
		现在的 Linux 桌面已经发展的很好了,在桌面下播放音乐操作起来也很简单.那么我们还记得在桌面不是那么好的时候我们是怎么播放音乐的么?哎,我是想不起来了,实在是太难了. 不过现在我们可以先安装一个小 ... 
- 【mark】linux 终端命令行下的快捷键(自己已验证所有)
		说明: \c + a:表示ctrl+a \a + a:表示alt+a 命令列表: 1 移动: \c + a:将光标移到行首 \c + e:将光标移到行尾 \c + f:将光标向后(右)移动一个字符 \ ... 
随机推荐
- 一文带你掌握Redis操作指南
			摘要:Redis是一种支持Key-Value等多种数据结构的存储系统. Redis是一种支持Key-Value等多种数据结构的存储系统.可用于缓存,事件发布或订阅,高速队列等场景.该数据库使用ANSI ... 
- 昇腾CANN:为你开启机器人开发的Buff 加成
			摘要:昇腾AI提供了全栈技术和产品,构筑人工智能的算力基座,赋能上层应用 本文分享自华为云社区<昇腾CANN:为你开启机器人开发的Buff 加成>,作者:华为云社区精选 . 昇腾AI基础软 ... 
- 一文详解什么是可解释AI
			摘要:本文带来什么是可解释AI,如何使用可解释AI能力来更好理解图片分类模型的预测结果,获取作为分类预测依据的关键特征区域,从而判断得到分类结果的合理性和正确性,加速模型调优. 1. 为什么需要可解释 ... 
- k8s源码Client-go中Reflector解析
			摘要:通过本文,可以了解Reflector通过ListWatcher从Kubernetes API中获取对象的流程,以及存储到store中,后续会对DeltaFIFO进行源码研读,通过结合inform ... 
- iOS打包IPA教程
			 转载:xcode打包导出ipa 众所周知,在开发苹果应用时需要使用签名(证书)才能进行打包安装苹果 IPA,作为刚接触ios开发的同学,只是学习ios app开发内测,并没有上架appstore需 ... 
- Codeforces Round #618 (Div. 2) A~E
			原作者为 RioTian@cnblogs, 本作品采用 CC 4.0 BY 进行许可,转载请注明出处. 1300A. Non-zero 题意:给你一个数组,每次操作你可以使其中任意元素的值+1,问最少 ... 
- 【驱动】SPI驱动分析(一)-SPI协议简介
			1. 什么是SPI SPI全拼Serial Peripheral interface(串行外围设备接口),是由Motorola(摩托罗拉)在MC68HCXX系列处理器上定义的,主要应用于EEPROM( ... 
- 嵌入式软件工程师笔试面试指南-ARM体系与架构
			哈喽,大家好.我终于回来了!19号刚提交完大论文,就被抓去出差了,折腾了整整一周,26号晚上,才回到学校.鸽了好久都没更新干货了.今天更新一篇关于Arm的笔试面试题目,文章内容已同步更新在github ... 
- S3C2440移植uboot之支持NORFLASH
			上节S3C2440移植uboot之支持NAND启动修改了代码支持了NAND启动.这节我们分析uboo使其支持NORFLASH的操作. 目录 1.分析启动错误 2.修改代码 3.在匹配数组中添加我们 ... 
- vue配置proxy实现跨域
