使用两个函数, inifetch和iniwrite
function ini_fetch()
{
if [ $# -ne 3 ]; then
return
fi
local file=$1
local section=$2
local key=$3
item=`sed -n '/^\['"$section"'\]/,/^\[/ {/^\['"$section"'\]/b; /^\[/b; /^'"$key"'\s*=.*/ p;}' $file`
if [ "${item}x" != "x" ]; then
value=${item#*=}
echo $value
fi
}
function ini_write()
{
if [ $# -ne 4 ]; then
echo 1
fi
local file=$1
local section=$2
local key=$3
local value=$4
sed -i '/^\['"$section"'\]/,/^\[/ {/^\['"$section"'\]/b; /^\[/b; s/^'"$key"'\s*=.*/'"$key"'='"$value"'/;}' $file
echo $?
}
例如配置文件如下:
[firmware_version] version=v1.1 RC1 [support_screen_size] count=3 screen_size0=320X240 screen_size1=480X272 screen_size2=800X480
$ ini_fetch ./lunch-cdr.ini "support_screen_size" "screen_size0"320X240
定义数组:
`ARRAY_NAME=()` 元素之间用空格作为间隔,并且用大括号括起来
获取数组中的所有成员:
`${ARRAY_NAME[@]}` 或者 `${ARRAY_NAME[*]}`
添加一个成员:
`ARRAY_NAME=(${ARRAY_NAME[@]} $new_combo)`
获取数组的长度:
${#ARRAY_NAME[@]}
取出数组中的第i个成员的值:
`${ARRAY_NAME[$i]}`
如何将数组作为参数传递给函数?
由于shell数组的功能很弱,无法直接作为参数传递,可以采用如下的方式转换:
例:
function test_array()
{
local i
local array1=(`echo $1 | cut -d " " --output-delimiter=" " -f 1-`)
local array2=(`echo $2 | cut -d " " --output-delimiter=" " -f 1-`)
for i in `seq 0 $((${#array1[@]} - 1))`
do
echo "array1 element $i: ${array1[$i]}"
done
for i in `seq 0 $((${#array2[@]} - 1))`
do
echo "array1 element $i: ${array2[$i]}"
done
}
array1=(test1 test2 test3 test4)
array2=(colin1 colin2 colin3 colin4 colin5)
test_array "$(echo ${array1[@]})" "$(echo ${array2[@]})"
运行结果如下:
$ ./array.sh
array1 element 0: test1
array1 element 1: test2
array1 element 2: test3
array1 element 3: test4
array1 element 0: colin1
array1 element 1: colin2
array1 element 2: colin3
array1 element 3: colin4
array1 element 4: colin5
注意: 传递的时候一定要使用"$(echo ${array1[@]})"这种方式,才能将整个数组作为一个参数传递
USB转串口设备在linux下的设备名为 /dev/ttyUSB* ckermit是一个linux下的串口工具, 需要配合配置文件~/.kermrc使用 ~/.kermrc的配置如下
set line /dev/ttyUSB1 set speed 115200 set carrier-watch off set handshake none set flow-control none robust set file type bin set file name lit set rec pack 1000 set send pack 1000 set window 5 set session-log TIMESTAMPED-TEXT
每次插拔USB转串口线,设备名都有可能变化,为了省去每次都要修改配置文件的步骤 写了如下的一个脚本来封装ckermit命令 https://github.com/caodan4linux/myserial
cat myserial
#########################################################################
# File Name: myserial
# Author: Dan.Cao
# mail: caodan2519@gmail.com
# Created Time: 2014年12月23日 星期二 11时57分14秒
#
# Description:
# manage the ckermit, connect to the serial port
# sudo permission my be needed by ckermit
#
# Date Author Comment
# 2014/12/23 Dan.Cao first version
# 2020/06/06 Dan.Cao generate ckermit configuration file
# support input baudrate
#########################################################################
#!/bin/sh
str=`ls /dev/ttyUSB* 2> /dev/null`
if [ "${str}x" = "x" ]; then
echo "not find the serial port!"
exit 1
fi
serial_ports=(`echo $str | cut -d " " --output-delimiter=" " -f 1-`)
serial_cnt=${#serial_ports[@]}
echo "find $serial_cnt serial ports:"
for i in `seq 0 $((serial_cnt - 1))`
do
echo -e "\t [$i]: \t $serial_ports[$i]"
done
echo -n "please select the port number:"
read choice
echo "choice is $choice"
#1. $1是脚本的第一个参数,这里作为awk命令的第一个参数传入给awk命令。
#2. 由于没有输入文件作为输入流,因此这里只是在BEGIN块中完成。
#3. 在awk中ARGV数组表示awk命令的参数数组,ARGV[0]表示命令本身,ARGV[1]表示第一个参数。
#4. match是awk的内置函数,返回值为匹配的正则表达式在字符串中(ARGV[1])的起始位置,没有找到返回0。
#5. 正则表达式的写法已经保证了匹配的字符串一定是十进制的正整数,如需要浮点数或负数,仅需修改正则即可。
#6. awk执行完成后将结果返回给isdigit变量,并作为其初始化值。
#7. isdigit=`echo $1 | awk '{ if (match($1, "^[0-9]+$") != 0) print "true"; else print "false" }' `
#8. 上面的写法也能实现该功能,但是由于有多个进程参与,因此效率低于下面的写法。
isdigit=`awk 'BEGIN { if (match(ARGV[1],"^[0-9]+$") != 0) print "true"; else print "false" }' $choice`
if [[ $isdigit != "true" ]]; then
echo "please input a digit number"
exit 1
fi
if [ $choice -ge $serial_cnt ]; then
echo "input number must less than $serial_cnt"
exit 1
fi
serial_port=${serial_ports[$choice]}
echo "select port is $serial_port"
# select Baudrate
read -p "Enter the baudrate (115200): " baudrate
if [ "${baudrate}x" == "x" ]; then
baudrate=115200
fi
echo "baudrate=${baudrate}"
#####################################################################
# generate configurations
#serial_port=dd
# 本来sed替换的分隔符是 '/', 但是会和路径变量serial_port中的'/'冲突,
# 所以使用冒号':' 代替之前的 '/' 分隔符
#sed -i 's:set line .*$:set line '"$serial_port"':' ~/.kermrc
CONFIG_FILE="/tmp/kermrc.${USER}"
cat > ${CONFIG_FILE} << GEN_KERMRC
set line ${serial_port}
set speed ${baudrate}
set carrier-watch off
set handshake none
set flow-control none
robust
set file type bin
set file name lit
set rec pack 1000
set send pack 1000
set window 5
set session-log TIMESTAMPED-TEXT
c
GEN_KERMRC
# start
ckermit ${CONFIG_FILE}
$ num=15
$ echo $((16#${num}))
$ 21
$ num=015
$ echo $((8#${num}))
$ 13
井号前面的数字表示进制
$ ((num=0x15))
$ echo $num
$ 21
$ ((num=015))
$ echo $num
$ 13
使用这种方式,对数字格式的要求: 16进制的数以0x开头, 8进制的数以0开头
3. 使用bc计算器实现
$ echo "obase=10; ibase=16; 12" | bc
$ 18
$ printf "%x" 127
$ 7f
$ printf "%d" 0x1f
$ 31
替换指定目录下所有文件中的字符串
例:将所有文件中的 RESBMPMLVOLUMELIGHT 替换为 RESBMPMLSILENTMODELIGHT
find ./newcdr -type f | xargs sed -i 's/RESBMPMLVOLUMELIGHT/RESBMPMLSILENTMODELIGHT/g'
调试shell脚本不需要什么特殊工具,bash本身就包含了一些选项,能够打印除脚本接受的参数和输入
使用选项-x, 启动跟踪调试shell脚本:
$bash -x script.sh
-x 将脚本中执行过的每一行都输出到stdout, 控制方式如下:
set -x 在执行时显示参数和命令 set +x 禁止调试 set -v 当命令进行读取时显示输入 set +v 禁止打印输入
例1:
#!/bin/sh set -x echo "I see!" mkdir sour
$ ./test.sh ++ echo 'I see!' I see! ++ mkdir sour mkdir: 无法创建目录"sour": 文件已存在
例2:
#!/bin/sh
for i in `seq 0 6`
do
set -x
echo $i
set +x
done
例3: 通过传递环境变量_DEBUG来控制调试信息
#!/bin/sh
function DEBUG()
{
[ "$_DEBUG" == "on" ] && $@ || :
}
for i in `seq 0 6`
do
DEBUG echo "i is $i"
done
执行结果:
$ ./test.sh $ _DEBUG=on ./test.sh i is 0 i is 1 i is 2 i is 3 i is 4 i is 5 i is 6
运行时如果没有设置_DEBUG=on,则不会看到echo输出的信息,是因为DEBUG函数中的命令 : 告诉shell不要进行任何操作
例:
path=dir1/dir2/dir3/dir4/filename.txt/file.txt
echo "path is: $path"
echo "path is: ${path#*/}" #删除 第一个/ 及其左边的字符
echo "path is: ${path##*/}" #删除 最后一个/ 及其左边的字符
echo "path is: ${path#*.}" #删除 第一个. 及其左边的字符
echo "path is: ${path##*.}" #删除 最后一个. 及其左边的字符
echo "path is: ${path%/*}" #删除 最后一个/ 及其右边的字符
echo "path is: ${path%%/*}" #删除 第一个/ 及其右边的字符
echo "path is: ${path%.*}" #删除 最后一个. 及其右边的字符
echo "path is: ${path%%.*}" #删除 第一个. 及其右边的字符
输出结果如下:
path is: dir1/dir2/dir3/dir4/filename.txt/file.txt
path is: dir2/dir3/dir4/filename.txt/file.txt
path is: file.txt
path is: txt/file.txt
path is: txt
path is: dir1/dir2/dir3/dir4/filename.txt
path is: dir1
path is: dir1/dir2/dir3/dir4/filename.txt/file
path is: dir1/dir2/dir3/dir4/filename
记忆方法:
在键盘上的位置: #位于$的左边, %位于$的右边.
所以使用#则表示从匹配字符左边开始删除, 使用%则表示从匹配字符右边开始删除 `#*/` 表示 匹配第一个`/`及其左边的字符 `##*/` 表示 匹配最后一个`/`及其左边的位置 `%/*` 表示 匹配最后一个`/`及其右边的位置 `%%/*` 表示 匹配第一个`/`及其右边的位置
其中*表示通配符,/表示希望匹配的字符是斜杠,也可指定其他的字符。
${str:n:m}
例:
$ str=string:xxx
$ start=${str:0:7}
$ echo $start
输出结果为: string:
${str:0:7}就是提取str中从第0个字符开始的7个字符。
例: 提取文件test.bin中的第12个字节开始的4个字节的内容 以16进制的格式表示:
$ od -A none -j 12 -N 4 -t x4 test.bin 310ad3cf
以10进制的格式表示:
$ od -A none -j 12 -N 4 -t d4 test.bin 822793167
option N指定需要dump的bytes数 option j表示跳过开始的多少bytes option t用于设置dump的格式 option 用于设置每行一的地址前缀格式,none表示不显示地址前缀
catch_signal()
{
echo "catch signal"
}
# when the signal 2 (SIGINT) is received, call catch_signal
trap "catch_signal" 2