Shell scripting 技巧积累

244 阅读3分钟

本文记录PhD期间出现的shell scripting代码问题以及解决办法.

1. 通过grep出数据并将其储存到变量当中

通过此方法得到的变量,变量后很有可能会有特殊字符,空格,回车之类的。而且很难发现,虽可通过检查字符串长度。 变量本身没什么问题,但如果要把他们加入到运算中,比如if 判断等等,就会出现问题。 解决方案如下:

tr -d '\r' or tr -d '\n' or sed 's/ //g'

例如:

a=$(grep ibrav $prefix.in|cut -d '=' -f 2|sed 's/ //g'|r -d '\r'|tr -d '\n'

具体可参照文章:blog.csdn.net/dingguanyi/…

2. 用rm递归递归删除子目录下所有.o后缀的文件

`find path/ -name *.o |xargs rm -f `#用 xargs 构造参数列表

同理可用于复制目录以及根目录下所有指定文件: 

`cp $(find /path/ -type f -name "*.sh") /tmp`

可通过 -maxdepth s设定搜索子目录的深度:
find . -maxdepth 1 -type f -name "xxx" 

表示只在当前目录搜索含有"xxx"字符的文件


3. 快速定位匹配字符的行号using awk

Line = $(awk '/String/{print NR}' file.txt)
或者
grep -n "text" file.txt (行数和匹配内容会一起打印出来)

其后可添加各种pipe

4. 用awk将指定行数范围的内容存入数组

Element = ( $(awk 'NR>=start_line && Nr<=end_line {print $1}') file.txt) #注意这个大括号。将元素先行后列的顺序依次存入列表

**#注意当两个行数为变量时,命令如下:** 

Element = ( $(awk "NR>=$start_line && Nr<=$end_line {print \$1}") file.txt)
重要: \$ 在这里的作用是在""之下,将 $1 重新转义为awk的字面意思

5. SED模糊匹配删除某行

sed -i "s/^$var.*.txt//" file.txt 
可形如这样任意组合

6.简易sed命令

sed -i 'Nd' file.txt #正删
sed -i '$d' #倒删

7. SED 直接显示指定行数范围的内容

sed -n ''$M','$N'p' file.txt 

8. sed -i "s/xxx/yyy/"

此命令表示的去替换是 每行 匹配的第一个目标,也就是说所有行的含有xxx的第一个地方都会被替换。
sed -i "s/xxx/yyy/g" 则表示将每行的所有匹配项替换掉 
如果只要全文中第一处出现的地方,则需要: 

sed -i '0,/pattern/{s/pattern/replacement/}' filename

9. 当使用Sed替换时,中间同时出现转译字符以及变量怎么办-SED的灵活运用

首先要知道''与""分别表示为直接显示以及展开运算并且sed -e s/xxxxxx/xxxxxx/ filename.txt 可以灵活的添加' '与" "到每个部分上比如:

1. sed -e s/$xxx/$yyy/ filename 
2. sed -e s/'$xxx'/$yyy/ filename
3. sed -e 's/$xxx/$yyy/' filename
特别注意一下情况:
sed -e s/\\n.*/\\n$name/ filename
此情况下\\n不需要被展开,但$name需要被展开所以就需要灵活搭配''"" 
sed -e 's/\\n.*/\\n'$name'/' filename 
在单引号中间再引入单引号即可展开变量。

bash关于提取数字与字母的方法以及变量嵌套的问题

此项工作原本想要批量修改文件名:

所以得分别提取出文件名中数字与字母.

om18.xyz -> 18_om.xyz 
a=(`ls|grep [0-9]`)
for ((i=0; i<${#a[*]}; i++ )); do
        filename="${a[i]}"
num="${filename//[!0-9]/}"
letters="${filename//[0-9]/}"

注意bash不支持,以下变量嵌套的形式。所以在中间引入了用一个filename的中间变量。

num="${${a[i]}//[!0-9]/}", letters="${${a[i]}//[0-9]/}" 

用sed命令匹配指定行并在其下一行进行修改

sed -e "/pattern/{n; s/search/replacement/}"

知识点在于n(next)以及s/p/{n; s/s/r/} 结构的使用

用find递归查找最深处或指定当前路径下的文件夹 比如说我想查找当前路径下递归(最深处)的带数字的文件夹,可以用如下find命令:

find . -name "*[0-9]" 

命令可以用于复制、移动、删除等操作十分方便.并且可以使用 -prune -o的命令,避开某些不想搜索的文件夹,

find . -type -d -path './18_rec' -prune -o -name '*[0-9]'

以上命令就可以在递归查找中,排除搜寻18_rec以下的所有文件与文件夹。 如果想要排除多个路径,则可使用以下命令:

find . -type d \( -path './18_rec' -o -path './l_rec' \) -prune -o -name "*[0-9]" -print

注意( -path './18_rec' -o -path './l_rec' ) 的用法以及-prune出现的位置。

sed只修改第一行中第一次匹配的元素

r18_rec.xyz #比如只删除第一个'r'
echo r18_rec.xyz | sed '0,/r/s//' 
#0代表第一行,s//此处结构代表把第一次出现的r删除掉

awk过滤某一列大于0的方法

awk -F" " '$1>0{print $1}' file 

-F 表示使用分隔符功能, " "表示使用空格作为分隔符, 1>0 即为判断语句第一列中大于0的数据, '{print 1}' 则是打印判断过后的第一列. 要注意的是, awk命令并不能像sed -i 一样在原文件中进行修改. 需要先输出到副本, 再进行覆盖

grep首行内容

grep -m 1 '^' filename

通过rsync备份数据

rsync -av ./* --exclude={'file1','file2'} ./

当需要保持文档目录结构,但又想排除某些文件时候,可以用--exclude={'file1','file2'}的结构来排除不想复制的文件。 尝试过用 find 命令找出这些文件,但是似乎find并不能保持根目录与子目录的结构。

awk 统计行数

awk 'END{print NR}' 统计行数

用awk 如何添加 if 条件

结构: awk 'if(conditions) {print $1,$2,$3...}"text"}' file name

显示当前目录下所以的子目录

ls -d * 
ls -v 按值排序显示

注意在-d 后面要加*