Some Useful Shell Resources
1. 将20类的图片按照类别copy到相应的文件夹
最近在用Deep learning工具caffe,基于数据集VOC做一些实验,里边有20个Object Class,所以得到结果后经常会遇到重复处理20遍文件。因此写了一些脚本,用来执行重复操作。
a. 以训练(Train)图片为例,首先根据每一类的初始列表如cat_trainval.txt(20个相同类型文件):
000005 0
000023 1
…
(ImageID Label)
得到每一类正例(Label=1)的文件名列表*.list:
for i in *_trainval.txt; do echo $i; grep " 1" $i | awk '{print $1}' > $i.list; done
b. 将该20个文件(cat_trainval.txt.list,…,etc),批量重命名成cat.txt格式方便后边操作:
for var in *.list; do echo "Processing $var..."; mv "$var" "`echo $var|awk -F '_' '{print $1}'`.txt"; done #批量重命名
c. 开始分类copy:
for j in cat dog person plane bike bird boat bottle bus car chair cow table horse motorbike plant sheep sofa train tvmonitor; do
for i in `cat $j.txt` ; do
mkdir $j;
cp ../../VOC2007train/VOCtrainval_06-Nov-2007/VOCdevkit/VOC2007/JPEGImages/$i.jpg ./$j/;
done;
done
2. 等待脚本:一旦某个条件符合,就执行特定操作
用GPU训练Caffe Model的时候,因为跟大家共享GPU资源,因此很多时候内存不够用,需要等待。简单写了个等待脚本,一旦发现GPU使用量有变化,就开始执行自己的task:
while [[ `nvidia-smi | grep 3862 | wc -l` -gt 0 ]]; do echo "wait..."; sleep 120; done; echo "Start!"; ./mytask.sh
(每隔120s查询一次while循环条件,终止条件可以根据情况自定义)
3. Caffe训练的时候,直接把所有的输出都record下来了,设置的是每一个iter都有输出,想要得到如每40个iters的平均的loss曲线
#!/bin/bash
# Usage: ./processLog.sh LogOrigionalName cat(or dog/flower...)
# Output file: LogOrigionalName-cat.csv
grep "Train net output" $1 | grep $2 | awk '{print $15}' > $1-$2.tmp
awk 'BEGIN{sum=0;}{sum=sum+$1;if(NR%40 == 0){printf("%.8f\n", sum/40); sum=0;}}' $1-$2.tmp > $1-$2.csv #利用awk求均值
rm $1-$2.tmp
4. 抽取某一个class如plant的feature,之后和其他class的ground truth结合成新的feature文件
在Train SVM model的时候,用了开源库liblinear,基于每一个class的输入图片list来抽取feature。
但是由于每个class的图片列表都相同,所以重复抽取feature不仅浪费时间而且没有意义,可以利用以下脚本组合成新的feature文件:
for i in `ls VOCtrainFilelist`; do #文件夹VOCtrainFilelist中有20个classes的list文件
echo "VOCtrainFilelist/$i"
sed 's/^[0-1]\s//g' plant/train_data.txt > 1.tmp #利用plant抽取好的feature,删除第一列label
awk '{print $2}' VOCtrainFilelist/$i > 2.tmp #ground truth列表,新class的label
paste 2.tmp 1.tmp > 3.tmp # 将2个文件合并成新class的feature文件(label+features)
done
rm 1.tmp 2.tmp 3.tmp
5. 对一个文件的某一列进行数值计算
有时会遇到某一列probability的ground truth打反了,需要将prob一列修改为1-prob:
awk '{printf("%s %.14f\n", $1, 1.0-$2)}' origin > origin-flip #源文件有2列,第2列为prob
6. 批量create20个class的lmdb文件
#!/bin/bash
# Usage: ./processLog.sh origionalNameList (./sh *_trainval.txt)
list=($@) # get input parameter's list
for i in ${list[@]}; do # loop over the parameters(different classes)
echo "Processing $i..." # for each class's file lists
awk '{print $2}' $i > $i-gt.tmp # get ground-truth label list(different from the caffe's requirement)
for val in `cat $i-gt.tmp` # flip labels: -1->0; 0->0; 1->1 (maybe `sed` could better fit the need)
do
if [ $val = "-1" ]; then
echo "0" >> $i-gt-VOC.tmp
elif [ $val = "0" ]; then
echo "0" >> $i-gt-VOC.tmp
else
echo "1" >> $i-gt-VOC.tmp
fi
done
paste list.txt $i-gt-VOC.tmp > $i.list
rm ./*.tmp
# use the list to get the lmdb
caffe.git/build/tools/convert_imageset -resize_height 256 -resize_width 256 -shuffle / $i.list $i-lmdb
rm ./*.list
done
7. awkfile的应用:先匹配,再操作
对于稍复杂的操作,不便于在一行命令操作,可以创建awk file供awk命令使用,比如之前用到的一个:
# Parse caffe logs
# Usage: awk -f log.awk logs > loss.csv
# Set output field seperator as comma used in .csv file
BEGIN { OFS = "," }
# Match loss lines
/.*] Iteration [0-9]+, loss = [0-9]+\.[0-9]+/ {
print format_time($2), $NF # call function, print "time + loss value"
}
function format_time(time) {
nano = substr(time, length(time) - 6) # use substr()
time = substr(time, 1, length(time) - 7)
# print time, nano
gsub(/:/, " ", time) # use gsub()
return time nano # return str
# return mktime(strftime("%Y ") month " " day " " time) nano
}
8. 查看某个文件有多少列
某个文件很长,列数不规则,可以通过以下命令判断,最多的大概有多少列:
awk '{if($7 != "") print}' list.txt | wc -l
9. 删除文件特定行
sed -i '/^$/d' filename # 删除空行
sed -i '/tags/d' filename # 删除匹配tags的行
10. vim中的匹配和替换
%s/_mean_[a-z]*.binary/_mean.binary/ # 将 “_单词“ 删掉
%s/_mean_.*512.binary/_mean_512.binary/g # 将512之前的单词删掉
11. function 函数的使用
#!/bin/bash
function fSum() // 函数定义 必须放在使用前
{
# echo $1,$2;
echo $(($1+$2)); // 如果没有显示的return语句,则最后一句作为返回值
}
t=$(fSum 3 2) // 相当于定义了fSum命令,传入参数
echo $t, $? // 5, 0,$?是上一句命令的返回值,0代表成功
log() { # classic logger
# 注意,shell函数中定义的变量是global的,其作用域从函数被调用执行变量的地方开始,到shell结束或者显示删除为止。函数定义的变量可以是local的,其作用域局限于函数内部,但是函数的参数是local的。
local prefix="[$(date "+%Y/%m/%d %H:%M:%S")]: "
echo "${prefix} $@" >&2 # 重定向到标准错误
}
log "INFO" "a message"
12. 批量杀死进程
ps aux|grep name|grep -v grep|awk '{print $2}'|xargs kill -9
13. 查看Linux内核版本或发布版本
lsb_release -a
cat /etc/issue
uname -a
14. 下载并安装某包
#!/usr/bin/env bash
LINK="http://.../download/gflags-2.1.2.tar.gz"
TARBALL=gflags_v2.1.2.tar.gz
WD=$(readlink -f "`dirname $0`/")
DOWNLOAD_DIR=${WD}/download
GFLAGS_ROOT=${WD}/gflags-2.1.2
INSTALL_DIR=${WD}/../build/
BUILD_DIR=${INSTALL_DIR}/build_gflags/
N_JOBS=8
[ ! -d ${DOWNLOAD_DIR} ] && mkdir -p ${DOWNLOAD_DIR}
cd ${DOWNLOAD_DIR}
if [ ! -f ${TARBALL} ]; then
wget ${LINK} -O ${TARBALL}
fi
cd ${WD}
rm -rf ${GFLAGS_ROOT}
cd ${GFLAGS_ROOT}
tar zxf "${DOWNLOAD_DIR}/${TARBALL}"
mkdir -p "${BUILD_DIR}"
cd "${BUILD_DIR}"
cmake -D... \
${GFLAGS_ROOT}
make -j${N_JOBS}
rm -rf "${INSTALL_DIR}/gflags"
make install/strip
cd "${WD}"
15. 批量重命名文件
某个文件夹下1.txt, 1000.txt, 批量重命名成000001.txt和001000.txt, 这样程序读取时可以按顺序
for i in `ls *`; do mv -- $i `echo $i | awk -F. '{printf("%06d\n", $1)}'`.txt; done # --避免$i开头有'-'
目录里包含很多子目录,每个子目录里有很多文件,将文件重命名将其目录名字加到前边
for i in `ls`; do pushd $i; ls | awk -v dir=$i '{print "mv " $1 " " dir$1}' | bash; popd; done
其中,注意awk需要external外部的变量时,需要用-v参数引入
16. 批量删除大小为0的文件
find . -name "*" -type f -size 0c | xargs -n 1 rm -f
17. 双层循环,依次取每100行,刪除空行
for j in {1..5}; do
for i in {1..15}; do echo $(($i*100)); head -$(($i*100)) dis1_$j.txt | tail -100 | awk '{print $8}' > tag$j/$j\_$i.txt; sed -i '/^$/d' tag$j/$j\_$i.txt; done
done
18. 統計代碼文件行數
wc -l `find . -name "*.cpp"` | awk 'BEGIN{sum=0;} {sum=sum+$1;} END{print sum}'
19. awk统计均值/最大值
# 求平均
awk '{sum+=$1} END {print "Average = ", sum/NR}'
# 求最大值
awk 'BEGIN {max = 0} {if ($1>max) max=$1 fi} END {print "Max=", max}'
# 求最小值
awk 'BEGIN {min = 1999999} {if ($1<min) min=$1 fi} END {print "Min=", min}'
20. 每隔10行统计一次均值,一共100行
for i in {1..10}; do grep "thread:" server.log | awk '{print $4}' | awk -F, '{print $1}' | head -$(($i*10)) | tail -10 | awk '{sum+=$1} END {print "Average = ", sum/NR}'; done