专栏首页机器学习与系统[翻译]15分钟bash进阶

[翻译]15分钟bash进阶

说明

更安全的脚本

每个脚本中我都以下面的内从开始:

#!/bin/bash
set -o nounset
set -o errexit

这会处理两个常见的错误:

  1. 引用未定义的变量(默认是””)
  2. 忽略执行失败的命令

这两个设置是有对应快捷写法的(”-u”和”-e”),但是原始写法更佳易读。

如果你要忽略可能执行错误的命令,可以使用下面的写法:

if ! <possible failing command> ; then
   echo "failure ignored"
fi

需要注意的是,有些Linux命令可以使用一些选项来强制忽略错误,比如rm -fmkdir -p

还需要注意的是,在“errexit”模式下,虽然能有效捕捉错误,但不能捕捉全部错误。在特定情况下,有些失败的命令没办法检测。(更多信息可以参考这篇文章

一位读者还推荐另一个用法set -o pipefail

函数

在Bash中你可以定义其它函数,它们和其它命令一样—你可以随意调用它们;这也会让你的脚本更具可读性。

ExtractBashComments() {
   egrep "^#"
}
cat myscript.sh | ExtractBashComments | wc
comments=$(ExtractBashComments < myscript.sh)

更多例子:

SumLines() {  # iterating over stdin - similar to awk      
   local sum=0
   local line=””
   while read line ; do
       sum=$((${sum} + ${line}))
   done
   echo ${sum}
}
SumLines < data_one_number_per_line.txt
log() {  # classic logger
  local prefix="[$(date +%Y/%m/%d\ %H:%M:%S)]: "
  echo "${prefix} $@" >&2
}
log "INFO" "a message"

尝试把所有bash代码移植到函数中,只留下全局变量/常量,然后在main函数中统一调用它们。

变量注解

Bash允许一种有限制的变量注解形式,最终要的有:

  • local(在函数内定义局部变量)
  • readonly(只读变量)# a useful idiom: DEFAULT_VAL can be overwritten # with an environment variable of the same name readonly DEFAULT_VAL=${DEFAULT_VAL:-7} myfunc() { # initialize a local variable with the global default local some_var=${DEFAULT_VAL} ... }

这样,你就可以把以前不是只读的变量声明成只读变量:

x=5
x=6
readonly x
x=7   # failure

尽量把bash中的所有变量注解成readonly或者local

用$() 代替 (`)

反单引号在一些字体中难以辨识,很容易和单引号混淆。

$()允许内嵌,而且避免了转义的麻烦

# both commands below print out: A-B-C-D
echo "A-`echo B-\`echo C-\\\`echo D\\\`\``"
echo "A-$(echo B-$(echo C-$(echo D)))"

[[]]代替[]

[[]]能够避免文件扩展名异常,提供一些语法上的改进,还增加了一些新的特性:

Operator(操作符)

Meaning(含义)

逻辑或

&&

逻辑与

<

字符比较(双中括号中不需要转义)

-lt

数字比较

=

字符串比较

==

以globbing的方式比较字符串,见下文 (仅双中括号有效)

=~

正则方式比较字符串,见下文(仅双中括号有效)

-n

字符串非空

-z

字符串为空

-eq

数字相等

-ne

数字不相等

单中括号:

[ "${name}" \> "a" -o ${name} \< "m" ]

双中括号:

 [[ "${name}" > "a" && "${name}" < "m"  ]]

正则和Globbing

以下几个例子能够体现出双中括号的强大能力:

t="abc123"
[[ "$t" == abc* ]]         # true (globbing)
[[ "$t" == "abc*" ]]       # false (literal matching)
[[ "$t" =~ [abc]+[123]+ ]] # true (regular expression)
[[ "$t" =~ "abc*" ]]       # false (literal matching)

注意,bash3.2以后正则表达式或Globbing表达式不能被引号包裹。如果表达式中含有空格,你可以存到变量中:

r="a b+"
[[ "a bbb" =~ $r ]]        # true

基于Globbing的字符串比较也可以用到case中:

case $t in
abc*)  <action> ;;
esac

字符串操作

bash有很多操作字符串的方法。

  • {#f}" # = 20 (string length) # slicing: {f: -8}" # = "file.ext"(Note: space before "-") pos=6 len=5 slice4="
  • {f//path?/x}" # = "x/x/file.ext" # string splitting readonly DIR_SEP="/" array=(
  • Deletion at beginning/end (with globbing) f="path1/path2/file.ext" # deletion at string beginning extension="${f#*.}" # = "ext" # greedy deletion at string beginning filename="${f##*/}" # = "file.ext" # deletion at string end dirname="${f%/*}" # = "path1/path2" # greedy deletion at end root="${f%%/*}" # = "path1"

避免使用临时文件

一些命令使用文件名作为参数,所以管道就无法使用了。这时<()就派上用场了,它可以接受一个命令,然后把命令转换成可以作为文件名的东西:

# download and diff two webpages
diff <(wget -O - url1) <(wget -O - url2)

“here document”也很有用,它允许把任意行字符串传给标准输入。

下面的MARKER可以换成任何文本:

# DELIMITER is an arbitrary string
command  << MARKER
...
${var}
$(cmd)
...
MARKER

内置变量

  • ! PID of the last command executed (and run in the background) ? exit status of the last command ({PIPESTATUS} for pipelined commands)
  • @ handles empty parameter list and white-space within parameters correctly @ should usually be quoted like so "

调试

对脚本进行语法检查

bash  -n myscript.sh

跟踪脚本里每个命令的执行:

bash -v myscript.sh

跟踪脚本里每个命令的执行并附加扩充信息:

bash -x myscript.sh

你可以在脚本头部添加set -o verboseset -o xtrace来永久指定-x-v

如果脚本运行在远程机器上这会很有效,用它来输出远程信息。

什么时候不该用脚本

  • 你的脚本很长,不下于几百行
  • 除了简单的数组外你还需要数据结构
  • 出现复杂的转义问题
  • 需要很多字符串操作
  • 不太需要调用其它程序或者通过管道和其它程序交互
  • 你比较在意性能

你需要考虑Python或者Ruby这样的脚本语言

参考

译者说

本文介绍了Bash中很多好的编程习惯和经验,字符串操作和比较是容易忽视以及不易掌握的。 注意bash中的正则和globbing的区别。

另外,本文有很多国人翻译了,译者在翻译本文时有一些翻译参考了《Bash脚本15分钟进阶教程》(http://www.vaikan.com/bash-scripting/),这篇翻译质量很高,我个人学习和借鉴了很多。

本文分享自微信公众号 - 机器学习与系统(aimlsystem),作者:Luke

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2017-04-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Linux Bash脚本15分钟进阶教程

    作者:Linux学习 ID:LoveLinux1024 这里的技术技巧最初是来自谷歌的“Testing on the Toilet” (TOTT)。这里是一个...

    小小科
  • Linux Bash脚本15分钟进阶教程

    这里的技术技巧最初是来自谷歌的“Testing on the Toilet” (TOTT)。这里是一个修订和扩增版本。

    小小科
  • 谷歌上线机器学习速成课程:中文配音+中文字幕+完全免费!

    【导读】3月1日,Google上线了AI学习网站——Learn with Google AI,并重磅推出了机器学习速成课程MLCC,该课程基于TensorFlo...

    WZEARW
  • 十分钟完成Bash 脚本进阶!列举Bash经典用法及其案例

    ? 前言:在linux中,Bash脚本是很基础的知识,大家可能一听脚本感觉很高大上,像小编当初刚开始学一样,感觉会写脚本的都是大神。虽然复杂的脚本是很烧脑,但...

    小小科
  • 十分钟完成Bash 脚本进阶!列举Bash经典用法及其案例

    前言:在linux中,Bash脚本是很基础的知识,大家可能一听脚本感觉很高大上,像小编当初刚开始学一样,感觉会写脚本的都是大神。虽然复杂的脚本是很烧脑,但是,当...

    小小科
  • 机器翻译界的BERT:可快速得到任意机器翻译模型的mRASP

    今天给大家介绍EMNLP2020的一篇关于多语言翻译新范式的工作multilingual Random Aligned Substitution Pre-tra...

    godweiyang
  • Shell基础 -- 入门篇

    shell 英文含义是“壳”,这是相对于内核来说的,shell 也确实就像是内核的壳,通常来说,所有对内核的访问都要经由 shell 。同时,shell 还是一...

    知忆
  • linux--shell

    eadela
  • 15分钟进击Kaggle大赛top2%

    对于从事机器学习行业的人来说,Kaggle比赛可能大家都耳熟能详,它是一个流行的数据科学竞赛平台。

    CDA数据分析师
  • 15分钟进击Kaggle大赛top2%

    读者朋友们,你们好,我是Abhay Pawar,平时热衷于参加一些机器学习的比赛,不知道你以前有没有听过kaggle比赛,如果你参加过就会知道这个比赛是非常有趣...

    统计学家
  • 15分钟进击Kaggle大赛top2%

    对于从事机器学习行业的人来说,Kaggle比赛可能大家都耳熟能详,它是一个流行的数据科学竞赛平台。

    大数据文摘
  • ​ mysql编译安装脚本

    这篇文章发布于 2015年,内容是介绍使用源码方式编译安装 mysql-5.6 ,时间回到 2015年,那时候 Docker还在蓄能阶段没有全面爆发。

    用户1560186
  • 技术漫谈 | 容器化开发及两步法快速构建Docker 镜像

    作为移动互联新时代的程序员,经常会把程序装进容器内运行,但是慢悠悠的镜像构建过程、国际网络的不稳定、移动联网时的流量狂奔,都让人又爱又恨。本文介绍的两步快速构建...

    CNCF
  • 哈工大自然语言处理工具箱之ltp在windows10下的安装使用教程

    ltp是哈工大出品的自然语言处理工具箱, pyltp是python下对ltp(c++)的封装.

    砸漏
  • GitHub五万星中文资源:命令行技巧大合集,新老司机各取所需

    技巧覆盖面广,且富含具体的例子。主要为Linux所写,却也有Mac和Windows的专用章节。

    AI算法与图像处理
  • 【译】三分钟掌握 React 高阶组件

    高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的...

    桃翁
  • 比特币总量为什么是2100万

    happy123.me
  • Dev 日志 | Segmentation Fault 和 GCC Illegal Instruction 编译问题排查

    笔者最近在重新整理和编译 Nebula Graph 的第三方依赖,选出两个比较有意思的问题给大家分享一下。

    NebulaGraph
  • Windows 10 开启 Liinux 子系统(WSL)

    打开控制面板 -> 程序和功能-> 启用或关闭 Windows 系统 -> 启用 Linux 子系统

    hedeqiang

扫码关注云+社区

领取腾讯云代金券