linux 命令收藏

一些很有用的命令

大杀器 sed

sed 用法:
d 删除
a 在下一行新增
i 在上一行插入
c 以行为单位的取代
-i 直接修改文件
-r ???

  • 替换
    sed -r -i 's/被替换字符/替换后的字符/g' fileName
    如果被替换的字符串中包含空格,???
    如果被替换的字符串中 有变量,把最外层的单引号改成双引号,如
    sed -r "s/160.268/$var/g" fileName
  • 替换多行
###C list
python<<EOF
import numpy as np
x=np.linspace(0,1,51)
y=x*x
f = open("Clist", 'w+')
for y in y:
print>>f,y
EOF
abc=`awk '{print $1}' Clist|tr "\n" "#"` # 将换行符替换成“#”,将abc缩为一行。
sed -i -e '{:begin; /)/! { $! { N; b begin }; }; s/C_param\n(.*)/C_param\n(\n'${abc}')/; };' ./file
# 将C_param下面的括号中的所有行,替换成abc。
sed -i 's/#/\n/g' ./fileName #将“#”替换成换行符,就是将abc还原成了一个多行数据。
这里用python先生成一个数组,然后输出到文件,然后读取这个文件,读取出来是一列数据,我打算将这一列数据替换掉某个文件中的一列其它数据。
  • 删除行
    sed -i '1d' fileName 删除第一行
    sed -i '$d' fileName 删除最后一行
    sed '/^\s*$/d' fileName 删除空行
    awk '!a[$0]++' fileName 删除重复行
    sed -i 1,35d fileName 删除1-35行
    sed -i 1~2d fileName 从第一行开始,每2行删除一行,即删除1··3··5··7··行。

  • 删除字符串
    删除字符串,即把它替换成空。
    sed -r -i 's/欲删除字符串//g' fileName

  • 删除文件中含特定字符串 abc 的行
       

    sed -e '/abc/d' fileName >fileName_NEW
    #这个操作好像不能使用 -i ,只能把结果重定向到一个新的文件
    sed -e '/abc/d' fileName >fileName
    #这样是不对的,生成的 fileName 是一个空文件

  • 修改文件中包含某个字符串的那一行(适合在脚本中修改 OpenFOAM的参数设置)
    参考
    比如:

#!/bin/bash
#PBS -N caseName
#PBS -l nodes=2:ppn=10
#PBS -j oe
#PBS -l walltime=150:30:00
cd $PBS_O_WORKDIR
NP=`cat $PBS_NODEFILE|wc -l`

n=`grep -n "numberOfSubdomains" system/decomposeParDict | awk -F':' '{print $1}'`
sed -i "$[n]c numberOfSubdomains $NP;" system/decomposeParDict
# 这里表示修改第 n 行,c 表示修改某一行

blockMesh
decomposePar -force
mpirun -np $NP -hostfile $PBS_NODEFILE reactingFoam -parallel 2>&1 | tee run.log

这里的 NP 就是所使用的核心数(这里等于 20),每次修改脚本的 nodes=2:ppn=10 这一行后,就可以不管下边的设置了,关键是不需要修改 decomposeParDict 文件了!因为有时候会忘记改这个参数。

大杀器 awk

基本用法: awk -F "用于分隔的符号或者字符串" '{print $分隔后你需要的列号}'
awk 提取某一列字符,如:

stp =     1    dt = 1.00e-09 s    ord = 1    time = 1e-06 ms	T_max =  897.7 K	T_st =  875.1 K

一个 log 文件,格式的每一行如上所示,现在需要提取 time 和 T_max 到一个新的文件,代码如下:

grep stp log | awk -F "=" '{print $5}'|awk -F "ms" '{print $1}' >time
grep stp log | awk -F "=" '{print $6}'|awk -F "K" '{print $1}' >temp
paste time temp | awk '{print $1"\t"$2}' >ignition.txt

解释,grep 是获取 log 文件中含有 stp 的所有行,awk 的主要功能是对列操作,这里按“等于”号将每一行分隔为若干列,然后取第 5 列,即第四个等于号和第五个等于号之间的字符串1e-06 ms T_max,然后将1e-06 ms T_max按ms分为两列,取第 1 列,即我们需要的“时间”。
第二行代码亦如此,获取到T_max,输出到temp文件。>大于号表示输出到文件,若该文件不存在,创建之;若存在,里边内容会被清空。如果使用两个大于号,则不同,>>表示输出到文件,但是是在文件末尾添加新写进去的内容。
第三行表示将time文件和temp文件合并成一个,time作为第一列,temp作为第二列。

列数为变量时如何使用:
awk -v N=274 '{ print $N}' fileName
获取第274列数据。

排序

sort -g # 可以对科学计数法进行从小到大排序
逆序:sort -g -r

循环、自增操作

for i in `seq 1 100`  
do
echo $i
done
files=`ls Pre*`
for file in $files
do
echo $file
done
transients=`ls *tout.kg|awk -F "t" '{print $2}'|awk -F "ms" '{print $1}'|sort -g`
x=10000
for transient in $transients; do
mv *"$transient"ms.tout.kg chi$x
x=`expr $x + 1`#自增
done

break跳出循环。
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

判断大小

推荐第三种!

if [ $T -lt 1200 ]; then  
语句块
fi
# 如果 T 小于1200,这里只使用于整数间的比较
if [ `expr $T \< $T_ext` -eq 1 ]; then 
# 如果 T 小于 T_ext
#不支持科学计数法,默认if成立,可能会出现 bug
if [ $(echo "$chi > $chi_ignition" | bc) -eq 1 ]; then 
# 如果 chi 大于 chi_ignition
#不支持科学计数法,默认 if 不成立,即跳过科学计数

PS:科学计数法转十进制:
方法1: printf "%f\n" 3.1188622400e+06
方法2: echo 3.1188622400e+06 | awk '{printf("%f\n",$0)}'

删除所有文件,except some file

find ./ -name '[^C][^1][^2]*' | xargs rm -rf #删除除了 C12 开头以外的其它文件

数组

index 从 0 开始
${abc[i]} 表示数组 abc 的第 i 个分量

实数运算

整数的加减乘除:

方法一:

b=$((5*5+5-6/2))
echo $b
输出:27

方法二:

i=5
c=`expr $i / 2`
echo $c
输出:2,可以看出,这里不支持小数
PS: 操作符号两边要有空格,这里的“/”也可以是“+”“-”“*”,*不行!

小数点位数

time=0.00015
time=$(printf "%.4f" `echo "$time + 0.0001"|bc`)
echo $time

输出:0.0002
保留4位小数,后边直接截断,不进行四舍五入。

time=0.00015
time=$(echo $time 0.0001 | awk '{ printf "%0.4f\n" ,$1+$2}')#time+0.0001
echo $time

输出:0.0003
四舍五入,保留4位小数。

浮点数的加减乘除:

方法一:

c=$(echo "5.01-4*2.0"|bc)
echo $c
输出:-2.99

例外:c=$(echo "1/1000"|bc)输出为0,因为它是小于1的小数。如何才能正确输出小数呢?

方法二:

c=$(awk 'BEGIN{print 7.01*5-4.01 }')
echo $c
输出:31.04
c=$(awk 'BEGIN{print 1/1000 }')
echo $c
输出:0.001

例外:我想输出从 0 到 1 之间的等间距小数

for i in `seq 0 10` 
do
c=$(awk 'BEGIN{print $i/10 }')
echo $c
done
输出 11 个 0
for i in `seq 1 10` 
do
c=$(printf "%.4f" `echo "$i / 10"|bc`)
echo $c
done
依然输出一堆 0.0000,只有最后一个是1.0000
for i in `seq 1 10` 
do
c=$(echo $i 10 | awk '{ printf "%0.4f\n" ,$1/$2}')
echo $c
done
这个才是正常输出的。

修改文件名

先来点简单的操作

增加后缀

find  . -type f -exec mv '{}' '{}'.old \;

增加前缀

for files in $(ls *.png)
do mv $files "pic."$files
done

去除前缀
???
去除后缀
???
网址

再来点高级的

将文件名拆分,然后重组,如:

ls fileName | sed -r -n 's/(.*)分隔字符(.*)/mv & 替换后的字符\1\2/e'
# 这里表示将原文件名按‘分隔字符’拆分为两部分,分别由(.*)对应,也对应 \1 和 \2。
# 后边的部分即为新文件名,可以添加任意字符在\1 \2的任何位置,也可以不要 \2,即删去“分隔字符”及其后边的部分。

举例:

ls chi* | sed -r -n 's/.*tf(.*)/mv & \1/e' 
# 分隔为 tf 之后部分,全部保留,即保留 tf 后边的字符串
# 原文件名:chi23.0769tf0363to0900Tst2227.kg
# 操作后:0363to0900Tst2227.kg

#  .* 加不加括号的区别在于,加括号后,才计入分隔的部分中;
# 如果不加括号,仅仅表示中间还有若干字符,但是不计入分隔后的部分。

ls chi* | sed -r -n 's/(.*)tf.*/mv & \1/e' 
# 分隔为 tf 之前部分,全部保留,即删去 tf 以及后边的所有字符串。
# 原文件名:chi23.0769tf0363to0900Tst2227.kg
# 操作后:chi23.0769

ls chi* | sed -r -n 's/(.*)tf.*.kg(.*)/mv & \1\2/e' 
# 分隔为 tf 之前,和 .kg 之后
# 这里分隔后,\1表示chi23.0769,即前边那个(.*)对应的部分,\2表示'AAA',即后边那个(.*)对应的部分。
# 原文件名:chi23.0769tf0363to0900Tst2227.kgAAA
# 操作后:chi23.0769AAA


ls chi* | sed -r -n 's/(.*)tf(.*).kg(.*)/mv & \1\2\3/e' 
# tf 和 .kg 把原文件名分隔为三部分,全部保留。
# 原文件名:chi23.0769tf0363to0900Tst2227.kgBBB
# 操作后:chi23.07690363to0900Tst2227BBB
文章作者: Yan Zhang
文章链接: https://openfoam.top/linuxLearning/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 OpenFOAM 成长之路
微信打赏给博主更多动力吧~