Chinaunix首页 | 论坛 | 博客
  • 博客访问: 427847
  • 博文数量: 101
  • 博客积分: 1547
  • 博客等级: 上尉
  • 技术积分: 1072
  • 用 户 组: 普通用户
  • 注册时间: 2006-01-12 23:46
个人简介

music,code,dialog,rest

文章分类

全部博文(101)

文章存档

2023年(8)

2022年(25)

2021年(6)

2020年(2)

2019年(6)

2018年(4)

2017年(5)

2016年(20)

2015年(4)

2014年(2)

2013年(1)

2012年(1)

2011年(1)

2010年(1)

2009年(2)

2007年(10)

2006年(3)

分类: LINUX

2015-06-20 07:52:53

在此记录下自己的一些经验:
Bash
A.关联数组参数传递。

关联数组在bash中是无法Export的,无法export也就无法进行大量的参数传递。
可以有几种办法来解决这个问题:
1. 如果是主体与内部函数之间传递,可以用eval模拟引用的方式解决。
2. 如果是进程和子进程之间,只将数据转化成参数[K1]=V1 [K2]=V2 [K3]=V3 的模式,到子进程内部进行再组合。返回也是用这种形式,用assocArray=($@)进行重构。

B. bash FUNCNAME数组
在写日志的时候,需要将信息的传递者体现出来,由于日志的输出方式基本都放在一个子函数中,在FUNCNAME功能还没出来的时候,基本都是这样调用:
    logmsg $debuglevel $funcname $msg

使用FUNCNAME后:
    这样用
    logmsg $debuglevel $msg

    内部如何知道是谁发出的消息呢?
    FUNCNAME是一个bash提供的系统Call Stack Array,所以每加一个Caller就从左向右shift进这个函数的名字。
    这样就容易了:
    只要${FUNCNAME[0]}, 永远是当前的子函数名字。那么${FUNCNAME[1]},就是Caller的名字。
    所以,使用该功能后,程序结构变更简洁清晰了。

C. 数组操作
普通数组和关联数组,区别
普通数组,index是整数
关联数组,index是string,value是另一个string
declare -A aArray
declare -a iArray

清空
aArray=()
iArray=()

访问方式:

直接分配元素
aArray=([S]=V1 [S]=V2 ... )
iArray=(V1 V2 ....)

在尾部添加

iArray+=(nv1 nv2 ...)

提取一个元素值
A=${iArray[N]}
A=${aArray[Key]}

提取所有元素值
${iArray[@]}    "${iArray[@]}" ${iArray[*]}  "${iArray[*]}"
${aArray[@]}    "${aArray[@]}" ${aArray[*]}  "${aArray[*]}"

数据分片提取,类似python slicing功能:
提取部分元素,Index 从M开始的N个元素(包含iArray[M])
${iArray[@]:M:N} 
${iArray[@]:M}    返回从M号元素到数据最后一个元素


数组元数据操作:
${#iArray[N]}    提取index为N的数组成员的String长度
${#aArray[String]} 提取key为String的aArray数组成员String长度
${#iArray[@]}  ${#aArray[*]}  返回数据元素个数
${!aArray[@]}  返回Key值组成的数组

删除数组:
unset -v iArray; unset -v aArray
unset -v iArray[@]; unset -v aArray[*]

删除一个数组元素:
unset -v iArray[N]; unset -v aArray[String]

Korn shell
由于Korn shell的一些优秀功能,使korn shell在programming的群中非常受欢迎,不是bash不好,而是只有korn shell才行。
但是没办法,bash已经成为linux的事实标准,korn只能成为骨灰级玩家的工具了。ksh93还是需要单独安装的。一般在比较重要的场合才会用一下。

A. lastpipe和命名管道
ksh天生的lastpipe功能,加上netcat+命名管道可以实现网络服务器双向通信的简单构架,在极其有限的资源环境中,可以构架简单实用的服务器进行验证测试。
使用如下结构:
点击(此处)折叠或打开
  1. while :; do
  2.  ( cat namedpipe | while read line:; do
  3.            processRequestbyLine $line;
  4. ) | netcat -lp $port >namedpipe
  5. done
B:支持天生的数据用户自定义数据类型,可以直接支持类似OOP的方式。
可以关注typeset -T的方式,定义一个类,可以有私有变量和公有方法, ksh居然可以这样使用。

点击(此处)折叠或打开

  1. #!/bin/ksh93
  2.  
  3. typeset -T Point_t=(
  4.      integer -h 'x coordinate' x=0
  5.      integer -h 'y coordinate' y=0
  6.      typeset -h 'point color' color="red"
  7.  
  8.      function getcolor {
  9.           print -r ${_.color}
  10.      }
  11.  
  12.      function setcolor {
  13.           _.color=$1
  14.      }
  15.  
  16.      setxy() {
  17.           _.x=$1; _.y=$2
  18.      }
  19.  
  20.      getxy() {
  21.           print -r "(${_.x},${_.y})"
  22.      }
  23. )
  24.  
  25. Point_t point
  26.  
  27. echo "Initial coordinates are (${point.x},${point.y}). Color is ${point.color}"
  28.  
  29. point.setxy 5 6
  30. point.setcolor blue
  31.  
  32. echo "New coordinates are ${point.getxy}. Color is ${point.getcolor}"
  33.  
  34. exit 0

C: 天生支持伪编译
shcomp, 本身就支持伪编译,suse自身已经带了,redhat系列好像没有。可以从网上单独安装。编译出来的伪码,需要加ksh scriptname执行,  直接vi,在头上加入#!/bin/ksh,居然就可以直接执行了。
bash还是需要shc的帮忙, 其实脚本也不指望能保护到什么地步,但是对现网的脚本加些保护,可以预防一知半解的人的破坏性尝试。这样的尝试对系统的破坏性还是很强的。


其他好用的功能 (bash 适用):

1. 字符串前后缀处理

删除前缀

abs 中的文件名称:(最长匹配)

a=/a/b/c/d/e/f/g/h; echo ${a##/*/}

h

abs中的root folder:(最短匹配)

a=/a/b/c/d/e/f/g/h; echo ${a#/*/}
/a
 


删除后缀

abs中的路径:(最短匹配)

a=/a/b/c/d/e/f/g/h; echo ${a%/*}

/a/b/c/d/e/f/g


2. eval和全局变量GLOBIGNORE的妙用
eval和GLOBIGNORE的使用
自动化中命令行的组建和Metachar的正确传递都是非常关键的。
在python中,命令基本都用triple quote和r前缀来disable所有meta char的功能。这也是python为啥这样流行又一好处。
在bash和ksh中,却没有这样的表达方式。有时候,要传送*的本身,而不希望*变成扩展成文件名。
我是这样实现的:
先组建命令字串。然后用eval 将字串当成命令去执行
当需要传送*或其他meta char时,先运行 GLOBIGNORE="${metachar}",指定需要disable glob的meta char。
eval运行完后,可以GLOBIGNORE=,清空该内置全局变量,恢复meta char的本身功能。

3. 完整的日志功能
还是日志的问题,有时候程序需要进行日志记录,如何在同时输出日志文件和终端消息的时候,不影响function使用的substitution的功能,由于substitution是占用stdout通道的。解决方法是可以,将所有日志输出到文件,同时将stderr和stdout彻底分开。
即, 让出stdout通道给substitution方式的功能调用,不影响function调用的正常的替换操作,所有日志相关的调试消息,同步输出到stderr和日志文件。
命令行很简单:
echo "blablabla" >&1 | tee -a $logfile >&2


4. 为没有时间戳的日志输出添加输出时间戳

依赖ts工具的实现方案
# install ts tools
apt-get install moreutils
do_something 2>&1 | ts


简单无依赖包的bash实现方案,
验证方案可行性的方法:
cat /var/log/boot.log | xargs -i bash -c 'sleep 1; echo "$(date): {}"'

实际使用时的方法:
do_something 2>&1 | xargs -i bash -c 'echo "$(date): {} "'

5. || &&

# (( 1 & 1)) || echo hello
# (( 0 & 1)) || echo hello
hello
# (( 0 & 1)) &&  echo hello
# (( 0 & 1)) ||  echo hello
hello
# (( 0 & 1))
# echo $?
1
# (( 1 & 1))
# echo $?
0

6. 发现关联数组的更新方式的不同点

associate["test"]=”anything”    和 associate+=(["test"]="anything") 还是不同的。
前者是更新元素
后者在appending元素

7. 用 for进行判断是否元素存在的好处。
a=($(command arg1 arg2))
for aa in ${a[@]}; do
     do somehting with aa
done

用统一的方式处理单个元素或多个元素。
如果没有正常返回内容,该段会直接跳过,而不会报错。
如果是其他if语句,如果处理不好容易发生报错现象。

8. indexof in shell 的几种实现

expr index String char
例如: expr index "hello world" o
5

s1="hello world"
s2=lo
match=${s1%%*$s2*}
${match:+:} eval "idx=$(expr "x${s1%$s2*}" : '.*')"
echo "${idx-0}"

4



20180528, Cloud Automation update
Zenith

阅读(1942) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~