shell从入门到放弃-优雅编程(1)

小K本着“能坐着绝不站着,能躺着绝不坐着”的“懒人之道”,努力打造规范和可靠的代码。下面就给大家讲讲小k在学习和使用shell过程中遇到的问题。

shell从入门到放弃-优雅编程(1)

0x00 前言

小K本着“能坐着绝不站着,能躺着绝不坐着”的“懒人之道”,努力打造规范和可靠的代码。下面就给大家讲讲小k在学习和使用shell过程中遇到的问题。

0x01 指令异常判断

今天真高兴啊,今天真兴高,小K一个小时就完成了今天的代码开发。小Q,来给我测试一下,马上就能上线。

<code>#!/bin/bash
echo '先将原数据文件a.txt做个备份'
cp a.txt bak.txt
echo '将原文件里的xx替换成yy'
sed -i "s/xxx/yyy/g" a.txt
###balabala省略一堆指令
echo '成功'/<code>

小Q:嘿嘿,来啦。不管三七二十一,先来个异常场景:a.txt不存在。

执行日志如下:

<code>先将原数据文件a.txt做个备份
cp: a.txt: No such file or directory
将原文件里的xx替换成yy
sed: 1: "a.txt": command a expects \ followed by text
成功/<code>

小Q:小K啊,代码都报异常了,最后告诉我成功。。。

小K:简单,我通过$?的值来判断上一步的状态进而决定是继续执行还是异常退出。(哼哼,为了防止小Q在找茬儿,我每个都加判断)

<code>echo '先将原数据文件a.txt做个备份'
cp a.txt bak.txt
if [ $? -ne 0 ];then
    echo 'command fail'
    exit 1
fi
echo '将原文件里的xx替换成yy'
sed -i "s/xxx/yyy/g" a.txt
if [ $? -ne 0 ];then
    echo 'command fail'
    exit 1
fi
###balabala一堆逻辑代码
echo '成功'/<code>

一顿操作猛如虎,原来10行的代码活生生变成了40行,有没有简单的方式呢?(幸亏公司不是拿代码行数做KPI,要不然我能写到公司破产)


那有什么方式可以优化一下呢?噔噔噔噔...答案就是:set -o errexit

<code>set -o errexit

echo '先将原数据文件a.txt做个备份'
cp a.txt bak.txt
echo '将原文件里的xx替换成yy'
sed -i "s/xxx/yyy/g" a.txt
###balabala一堆逻辑代码
echo '成功'/<code>

Tips:

  1. 一旦有任何一个指令返回非0值,则异常退出,此时$?将不起作用
  2. 如果需要程序出错也继续执行,可以在执行命令前加if判断或者在命令上追加“ || true”

0x02 函数化

小K作为努力“粪”发向上的有为“青年”,把日志打成这样实在是让人看不下去,至少得加个时间戳吧。

这个不难,通过date就行,但这一行一行的替换着实不像我这个懒人的风格。

马上中午了,被小Q折腾的连水都没喝一口,直接上代码:

<code>#具体格式可以自行定义,这里以 时间 日志级别 日志信息展示
function logger() {
    echo $(date "+%Y-%m-%d %H:%M:%S")" $1:$2"
}

logger 'info' '先将原数据文件a.txt做个备份'
cp a.txt bak.txt/<code>

Tips:

  1. 公用代码,业务逻辑都可以封装到函数。简单明了,可读性强。

0x03 参数传递

小P:小K,小Q来一下。我突然想到原数据文件可能不叫a.txt,我又不想改文件名。你们给搞下。

小K:(又改需求,一脸黑线。。。) 那我加个外部参数传递吧: sh xxx.sh a.txt

<code>source=$1
logger 'info' "先将原数据文件[${source}]做个备份"
cp ${source} bak.txt/<code>

小Q:如果后面还要加功能,需要传入多个参数呢?

小K:嗯。。。使用$1的方式,代码里肯定还得需要定义多个变量,有点刷代码行数的嫌疑,而且如果不小心传错位不好判断。

这样的话小K就只能出杀手锏了:sh xxx.sh source=a.txt target=bak.txt

<code>for i in $*
do
    export $i
done
logger 'info' "将原数据文件[${source}]复制到[${target}]"
cp ${source} ${target}/<code>

Tips:

  1. 可以通过循环的方式和export直接将外部参数赋值给变量

0x04 变量未定义

哼哼哈hi,搞定。等等,万一小Q又来个异常测试,不给我传变量名可咋整?

可以在代码里加上set –o nounset。

<code>for i in $*
do
    export $i
done
set -o nounset

logger 'info' "将原数据文件[${source}]复制到[${target}]"
cp ${source} ${target}/<code>

Tips:

  1. 当使用未定义的变量时,设置set -o nounset 可以让程序强制退出。老板再也不用担心rm -rf /${xxx}

这些小技巧你学会了吗?

I will be back!


作者:范令凯

公众号:互联网技术到家

头条号:互联网技术到家


分享到:


相關文章: