文档章节

Shell 特殊用法续

cwalet
 cwalet
发布于 2015/04/17 09:49
字数 1894
阅读 6.5K
收藏 166

1.函数中输出函数名:$FUNCNAME

注意该变量是一个数组,如果嵌套调用函数,那么最里层函数中的此变量会是按调用顺序排列的所有函数的数组,如:

function log() {
    echo ${FUNCNAME[@]}
}
function action() {
    log
}
action

输出内容是:log action

如果只想获得当前函数的名称,直接输出即可:echo $FUNCNAME

用途:日志函数或者函数名传递等。

参考:Bash 获取当前函数名


2.循环中的跳转:continue [n]

首先需要声明的是continue可用于子函数,跳转到父函数中的指定层次循环。如:

function son() {
    for z in 1 2 3; do
        if true; then
            echo $x,$y,$z
            continue 3
        fi
    done
}
function father() {
    for x in 1 2 3; do
        for y in 1 2 3; do
            son
        done
    done
}
father
  • n的值从1开始(不写默认为1,数字越大则层数越高,超过总循环层数时值为最大层数);
  • 以上代码中只有最上层"x"会正常循环完,其余子层都在首轮跳出,此时n的最大值为3;
  • 若在son后加一个“&”使其在后台运行,此时continue能控制y、z两层,但不能跳转到x,即n的最大值为2。


3.uniq注意事项

Note: 'uniq' does not detect repeated lines unless they are adjacent.
该命令容易被忽略的一点是,它只会比较相邻的行而不会跨行比较,除非必要,否则最好先排序: sort -u


4.变量间接引用(indirect expansion)

两种方法见如下代码:

a=1
b=a
echo ${!b}
eval echo \$$b

参考:shell 间接变量引用的问题Parameter Expansion


5.sed模式空间

以下4种用法,第一个会替换每一行的第一个小写a,第二与第四个则会替换所有小写a,第三个只会替换第一行的第一个小写a:

printf 'aaa\naaa' | sed 's/a/A/'
printf 'aaa\naaa' | sed 's/a/A/g'
printf 'aaa\naaa' | sed ':a;N;$!ba;s/a/A/'
printf 'aaa\naaa' | sed ':a;N;$!ba;s/a/A/g'

但是如果原始数据只有一行,那么最后两种写法均不会生效,

因此最好的写法是只替换第一行的第一个字符:printf 'aaa\naaa\n' | sed '1s/a/A/'

参考:让sed只替换一次


6.条件表达式

( ! [[ '123' =~ ^[0-9]+$ || 1 -gt 0 ]] ) && echo 1 || echo 2
( ! [ 1 -eq 2 -o 1 -gt 0 ] ) && echo 1 || echo 2
[ ! 1 -eq 2 -o 1 -gt 0 ] && echo 1 || echo 2
! [ 1 -eq 2 -o 1 -gt 0 ] && echo 1 || echo 2
注意:
  • 带正则表达式的条件语句必须要写在双中括号“[[]]”中;
注意:在[] 表达式中,常见的>,<需要加转义字符,表示字符串大小比较,以acill码 位置作为比较。 不直接支持<>运算符,还有逻辑运算符|| && 它需要用-a[and] –o[or]表示
注意:[[]] 运算符只是[]运算符的扩充。能够支持<,>符号运算不需要转义符,它还是以字符串比较大小。里面支持逻辑运算符:|| &&
  • 如果要对整个条件语句取反,最好是将“!”写在“[]”之外,并且尽量用“()”包围起来;
  • 以上第三种写法没有达到要求,第四行不推荐,推荐前两种写法;
不考虑对低版本bash和对sh的兼容的情况下,用[[]]是兼容性强,而且性能比较快,在做条件运算时候,可以使用该运算符。


7.awk输出单引号

awk '{print "'\''"}',注意反斜杠后面是两个单引号。

解释:这是shell的问题,以上代码其实是三个引用(引用自blackold):

  • '{print "'
  • \'
  • '"}'

shell解释后,awk看到的是:{print "'"}

参考:http://bbs.chinaunix.net/thread-1692469-1-1.html


8.删除UTF8文件中的BOM

「带 BOM 的 UTF-8」和「无 BOM 的 UTF-8」有什么区别?

简单来说BOM被微软用于区分UTF-8 和 ASCII编码文件,但是Linux中使用的UTF8标准不包含它

因此在执行包含BOM的UTF8编码的脚本的时候会报错:M-oM-;M-?#!/bin/bash$

用Win记事本保存的UTF8文件都会在文件头部包含一段不可见字符

查看:cat -A file | head -1 。去除方式有:

tail -c +4 old_file > new_file
grep -rIl $'^\xEF\xBB\xBF' . | xargs sed -ie '1s/\xEF\xBB\xBF//'
find . -type f -exec sed '1s/^\xEF\xBB\xBF//' -i.bak {} \; -exec rm {}.bak \;

或者通过vim命令: :set nobomb(删除)、:set bomb(保留)


9.函数动态参数

function fun() {
    echo $9,$10,$11,$12
    names=('a' 'b' c d e f g h x j k l)
    for i in $(seq 1 $#); do
        eval ${names[i-1]}=\'${!i}\'
        echo ${names[i-1]}=${!names[i-1]}
    done
}
fun 1 2 3 "4 5" 6 7 8 9 10 11 12 13

以上函数第一行输出的结果是:10,10,11,12

第2行开始结合使用数组、变量间接引用通过循环来赋值参数。

但是为什么“$10”不为11而重复一次,为何通过变量间接引用的时候又能正确输出?先往下看。

参考:Linux 技巧: Bash 参数和参数扩展


10.shift的用法

function fun() {
    local params=('a' 'b' c d e f g h x j k l others)
    local a b c d e f g h i j k l others
    for i in $(seq 1 $#); do
        if [ $i -le 12 ]; then
            eval ${params[i-1]}=\'$1\'
        else
            eval others=\'$others$1\'
        fi
        shift
    done
    for i in $(seq 1 ${#params[*]}); do
        echo ${params[i-1]}=${!params[i-1]}
    done
}
fun 1 2 3 "4 5" 6 7 8 9 10 11 12 13 14 15 16

shift [n]:其作用就是将n+1的参数位移到1,n不能大于最大参数个数,为0无效,默认为1。

以上脚本中,for循环里的shift每循环一次将参数位左移1位,使得“$1”始终取得的是逐一往后的参数;

最后再将剩余的参数全部赋值给others。


11.$BASH_REMATCH 用法

bash3.0以上版本扩展运算符“[[]]”中可用,该变量是一个数组,

实现了正则匹配的分组功能,类似于sed中的下标分组法:\n

echo "
<List>
    <Job id=1 name=abc/>
    <Job id=2 name=zyz/>
    <Job id=3 name=beew/>
</List>" | while read line; do
    if [[ $line =~ id=([0-9]+).*name=([^/]*) ]]; then
        echo ${BASH_REMATCH[1]} : ${BASH_REMATCH[2]}
    fi
done

参考:bash 自带正则匹配功能 - BASH_REMATCH 介绍

更多内置变量参考:Bash Variables,中文版(不全):Shell Variables 变量


12.关于 IFS=$'\n'

该用法被称作:ANSI C-quoted strings

bash中定义了一种申明特殊字符变量的写法:$'string'

在重定义系统变量IFS的时候经常用到,IFS的默认值为“<space><tab><newline>”,

经过美元符号修饰的换行符变成了事实上的换行符,而非两个字符“\”和“n”。

参考:Bash/shell scripting: What is the exact meaning of IFS=$'\n'?


13.让for循环支持多个参数

当然这里并没有直接给for循环声明多个参数(语法不支持),而是通过一些小把戏来实现的:

xyz='a b
c d
e f'

function fun() {
    local a b i
    OLD_IFS=$IFS
    IFS=$'\n'
    # 注意该处变量xyz不能加引号包围
    for i in $xyz; do
        # [临时变量]和[过程替换]结合使用
        IFS=$OLD_IFS read a b < <(echo $i)
        echo $a,$b,$i
    done
    # 还原默认分隔符
    IFS=$OLD_IFS
}

fun

注意:

  • shell 中定义的变量都是全局变量,使用local(仅可在函数中使用)可以定义局部变量,在并发时全局变量很容易引起混乱
  • read 读取内容的默认分隔符同样是“$IFS”,因此执行 read 读取变量前一定要将 IFS值还原。
  • 关于“过程替换(Process Substitution)”,请参看我之前的文章:SSH循环连接


14.to be continued

© 著作权归作者所有

cwalet
粉丝 44
博文 111
码字总数 87663
作品 0
其他
私信 提问
加载中

评论(7)

小译译
楼主总结的很好,bash只是linux上用的比较多,如果是aix或者hp不一定好使,建议使用ksh
纳兰清风
纳兰清风
mark
Feng_Yu
Feng_Yu
战略Mark
wharf_zhang
wharf_zhang
总结得够深度,我喜欢,收藏了,谢谢。欢迎继续。
baiwenl
baiwenl
好,收藏起来。。
y
yiranwuqing
很赞
OSChina 技术周刊第三十期 —— IT 公司开源软件整理计划

每周技术抢先看,总有你想要的! 移动开发 【翻译】Intel® INDE for Google Android Studio 【软件】移动应用开发框架 Samurai-Native 【博客】學習 React.js:用 Node 和 React.js 創建一個...

OSC编辑部
2015/04/19
4.2K
9
Linux shell 命令行参数

Linux shell 命令行参数 $数字的用法 ($0除外) #!/bin/bash test $ useful value=$1echo $value //写法./test$ 10 10 $# 用法 #!/bin/bash test $ useful value=$# //参数的数量echo $value......

年少爱追梦
2016/05/01
84
2
linux常见上传下载,以及跨机器文件传输命令总结。

linux常见上传下载,以及跨机器文件传输命令总结。 近来项目完成了,搭建测试环境时,需要下载一些软件,还有由于堡垒机的存在,多个服务器之间文件的相互拷贝,十分麻烦,特来总结了一下,加...

奇葩界张三
2017/04/26
0
0
shell 括号的特殊用法

Shell中的括号有其特殊的用法, 现总结如下: 1. 符号$后的括号 ${a} 变量a的值, 在不引起歧义的情况下可以省略大括号. $(cmd) 命令替换, 结果为shell命令cmd的输出, 和效果相同, 不过某些She...

高健2013
2015/02/11
0
0
2018-6-19bash编程之循环

我们继续将bash脚本编程,回顾一下程序的执行流程,分别为: 顺序执行选择执行循环执行 而对于循环执行来说,其分类涉及到以下几种: for, while, until 每个循环都有执行条件和退出条件,这...

谁猜谁知道
2018/06/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

定时器Timer和TimerTask

为什么要使用定时器呢? 比如说一个web应用,如果这个应用规模很大,那它的日志数据是不是很多。如果一直存下来服务器的存储量怕是不行吧,需要隔一段时间删除,那么就需要一个线程每隔一段时...

南柯好萌
39分钟前
18
0
深圳创服机构创成汇投融资对接指南

深圳创服机构创成汇投融资对接指南 一线城市一直是许多创业者创业热土,深圳也不例外,作为发达城市,科技是深圳的标志,也是许多科技创业者向往之地,科技创业者在创业前期面临许多难题,其...

cchlin
51分钟前
35
0
egg学习笔记第六天:使用中间件屏蔽可疑用户

站点有时候想屏蔽一些特定频繁抓取服务器数据的用户,可以放在中间件中去做,用户在指定Ip数组内,则屏蔽,如果不在,则匹配路由规则执行controller。 中间件的概念: 匹配路由前,匹配路由完...

一生懸命吧
56分钟前
34
0
005-其他技巧

css精灵图(css雪碧)sprites 减少服务器接收和发送请求的次数,提高页面加载速度 原理:将网页中的一些小背景图整合到一张大图中 使用background-position移动背景图位置-x/y坐标 字体图标ico...

沉默的懒猫
今天
15
0
YouTube视频下载:Airy for mac

想在YouTube下载视频?借助适用于Mac的AIry YouTube下载程序,您可以获得一个简单而高效的下载程序,可以在瞬间处理来自YouTube的任何曲目或播放列表。只需找到您要下载的视频,选择格式和分...

MacW软件分享
今天
38
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部