June 2014 Blog Posts

Python函数的各种参数(含星号参数)

MitchellChu 2014-06-23 编程语言

Python中函数的有4种形式,分别是:

  1. 位置或关键字参数(Positional-or-keyword parameter)
  2. 仅位置的参数(Positional-only parameter)
  3. 任意数量的位置参数(var-positional parameter)
  4. 任意数量的关键字参数(var-keyword )

第一种:位置或关键字参数

这种参数是中默认的参数类型,定义这种参数后,可以通过位置参数,或者关键字参数的形式传递参数:

## 位置或者关键字参数
## 这个是Python的默认参数类型
## 示例:arg2提供了默认value
def func(arg1, arg2="World!"):
    print arg1, arg2

## func可以通过位置参数形式调用
func("Hello", "MitchellChu")

## 也可以通过关键字参数的形式来调用func
func(arg1="Hello", arg2="World!")

## 当然,混合的方式也是完全没有问题的
func("Hello", arg2="World!")

## 不过如果你不能将关键字参数优先于位置参数传递给函数(方法)
## 这个调用方法是不能接受的,因为优先级不一样.后面会说
func(arg1="Hello", "World!") ## ERROR

 第二种方式:仅适用位置参数的形式

这种形式在需要将参数传递给函数(方法)时,仅能通过位置参数的传递方式。这种形式对于Python的开发者来说,暂时并没有办法使用。这种形式现在仅存在Python的很多内建的函数上:

## Positional-only parameter has no syntax to define
## 虽然无定义方法,但内建的很多函数都是仅接受位置参数的
abs(-3) ## correct
abs(a=3) ## wrong

## Traceback (most recent call last):
##   File "<stdin>", line 1, in <module>
## TypeError: abs() takes no keyword arguments


pow(x=2,y=3)
## Traceback (most recent call last):
##   File "<stdin>", line 1, in <module>
## TypeError: pow() takes no keyword arguments

pow(2,3)
## 8

 第三种:任意数量的位置参数(带单个

任意数量的位置参数在定义的时候是需要一个星号前缀来表示,在传递参数的时候,可以在原有参数的后面添加任意多个参数,这些参数将会被放在元组内提供给函数(方法):

## var-positional parameter
## 定义的时候,我们需要添加单个星号作为前缀
def func(arg1, arg2, *args):
    print arg1, arg2, args

## 调用的时候,前面两个必须在前面
## 前两个参数是位置或关键字参数的形式
## 所以你可以使用这种参数的任一合法的传递方法
func("hello", "Tuple, values is:", 2, 3, 3, 4)

## Output:
## hello Tuple, values is: (2, 3, 3, 4)
## 多余的参数将自动被放入元组中提供给函数使用

## 如果你需要传递元组给函数
## 你需要在传递的过程中添加*号
## 请看下面例子中的输出差异:

func("hello", "Tuple, values is:", (2, 3, 3, 4))

## Output:
## hello Tuple, values is: ((2, 3, 3, 4),)

func("hello", "Tuple, values is:", *(2, 3, 3, 4))

## Output:
## hello Tuple, values is: (2, 3, 3, 4)

第四种:任意数量的关键字参数(带两个星号参数)

任意数量的关键字参数在定义的时候,参数名称前面需要有两个星号(**)作为前缀,这样定义出来的参数,在传递参数的时候,可以在原有的参数后面添加任意多个关键字参数,关键字参数是使用[参数名称=参数值]的形式进行传递:

## var-keywords parameter
## 定义的时候,需要两个星号作为前缀
def func(arg1, arg2, **kwargs):
    print arg1, arg2, kwargs

func("hello", "Dict, values is:", x=2, y=3, z=3)

## Output:
## 多余的参数将自动被放入字典中提供给函数使用

## 如果你需要直接传递字典给函数
## 你需要在传递的过程中添加**
## 此时如果还有关键字参数应在字典前提供完成
## 不能在字典后再提供
## 请看下面例子中的输出差异:

func("hello", "Dict., values is:", **{'x':2, 'y':3, 'z':3})
## hello Dict., values is: {'y': 3, 'x': 2, 'z': 3}

func("hello", "Dict., values is:", **{'x':2, 'y':3, 'z':3,})
## hello Dict., values is: {'y': 3, 'x': 2, 'z': 3}

func("hello", "Dict., values is:", {'x':2, 'y':3, 'z':3})
## Traceback (most recent call last):
##   File "<stdin>", line 1, in <module>
## TypeError: func() takes exactly 2 arguments (3 given)

func("hello", "Dict., values is:", s=3, **{'x':2, 'y':3, 'z':3,})
## hello Dict., values is: {'y': 3, 'x': 2, 's': 3, 'z': 3}

## 提供了重复的参数
func("hello", "Dict., values is:", y=3, **{'x':2, 'y':3, 'z':3,})
## Traceback (most recent call last):
##   File "<stdin>", line 1, in <module>
## TypeError: func() got multiple values for keyword argument 'y'

 总结:四种参数形式中仅有第二种Python没有提供定义的方法,其他三种在定义的时候也需要注意,定义的时候应该根据Python的解析规律进行定义,其中:

  1. 位置或关键字参数应该在最前面,其中,没有默认值的应该在有默认值的参数前面
  2. 任意数量位置参数应该放在所有位置或关键字参数的后面
  3. 任意数量关键字参数应该放在任意数量位置参数的后面

注意:任意数量位置参数和任意数量关键字参数只能在定义中定义一次。

## 各种参数的混合使用例子
## Author: MitchellChu

def func(arg1, arg2='default', *args, **kwargs):
    print "arg1=%s, arg2=%s, args=%s, kwargs=%s" % (arg1, arg2, args, kwargs)


func(1) ## correct
func(1,2) ## correct
func(1,2,3,4) ## correct
func(1,2,3,4,x=1,y=2) ## correct
func(1,2,x=1) ## correct

func(x=1) ## wrong
func(arg1=1) ## correct
func(1,x=1) ## correct

## 可以将例子保存到parameter.py文件
## 而后运行python /path/to/parameter.py

 

Linux任务的高级管理:程序后台运行及控制

MitchellChu 2014-06-18 Unix & Linux

下操作,不可避免的需要让程序运行在后台而不妨碍前台的操作。在Linux有个概念称之为Job Control,由于Bash下的运行的任何程序都是当前Bash下的子程序,而job control也即管理当前Bash下的子程序。所以,Job Control的概念是不能跨Bash管理,比如我们不能在tty1中管理tty2中的程序。

其中我们在Bash中最常用的应该就是&符了,这个符号跟在要运行的程序的后面,像下面这样:

ping blog.useasp.net &

这样配置后,我们将会发现,运行后,系统返回的是类似下面这样的:

[1] 23911

这样我们就将这个ping放到了当前Bash的后台进行运行,我们此时仍可以正常的在Bash下进行其他的操作。但是你也许会发现这种方式运行的程序虽然不影响你当前操作,但是运行的输出却总是和我们抢占Bash的屏幕,非常的郁闷!但当我们想Ctrl+C来终止的时候,却又无能为力——因为在Bash下你Ctrl+C根本无法终止这个后台运行的程序!

为了防止这种情况,我们需要用到重定向(Redirection),如果你不太清楚,可以本博客之前的博文《Linux下高效编写Shell-Shell特殊字符汇总》篇里面的重定向,代码变化不大,类似下面这样:

## 重定向输出到/dev/null这个特殊文件
## 也就是没有输出内容了
ping blog.useasp.net &>/dev/null &

当然,我们一般更希望后台运行的程序的输出能够保存到指定文件,而不是直接丢弃,所以更一般形式是:

ping blog.useasp.net >>/tmp/background_programs.log 2>&1 &
## 想想这是什么意思?

但我们在这里是要Bash界面能够不被后台的程序搞砸。——毫无疑问,我们前一种已经达到了我们要的效果。

 恩,迄今为止我们已经能够将程序放到后台运行了,但是,对于已经占据我们Bash的程序,我们却无能为力,为了不让它们继续霸占我们的Bash屏幕,我们迄今能做的只有Ctrl +C,让它见鬼去吧!这样我们跑了很久的程序也就终结了,不过,运行的数据可能也没有了。也许更温柔一点是个不错的选择——Ctrl+Z

Ctrl+Z是让程序暂停,在已经运行的程序上直接按下Ctrl+Z,他们就会非常自觉的将自己挂起,并放入到后台中,此时的程序是处于停止状态的,如果要让他在后台运行,就还要用到后面将学到的命令。但此时,我们的Bash屏幕能恢复干净清爽才最主要。

 好了,在这难得平静的Bash界面上,让我们来学习下的一个命令吧,也许我们后台已经有一堆程序在跑呢,我们怎么也得看看才放心,命令就是让我们干这个事情的:

jobs [-lnprs] [jobspec ...] or jobs -x command [args]
参数:
-l    列出后台程序的job number,PID, 状态和命令串
-n    显示自从上次用户知晓状态后程序改变过状态的程序
-r    仅列出正在后台运行(RUNNING)的程序
-s    仅列出后台中处于停止(STOPPED)的程序
更详细的内容可以参看man,这里基本够我们用了。

用用看,你也许会发现你的后台有很多程序在运行哦,同时你也会看到一些不同的地方,比如:

jobs -l
[1]- 10314 Running                 ping blog.useasp.net &>/dev/null &
[2]+ 10833 Stopped                 emacs (wd:~)

中括号后面的竟然有+和-号,这是什么?这个是Bash根据我们放入后台的顺序的一个标记,+号表示最近被放到后台的程序,-号次之,如果有三个以上,我们就会发现第三个以上是没有+/-符号的。而下面我们将要看到的fg在取出后台程序的时候,+号在默认情况下就是那个被切换到前台的程序了。

既然上面我们说了,那就看看它是干什么的。fg应该是foreground的简写,即前台,它的作用是将在后台的程序切换到前台来运行。在切换的时候,fg可以指定参数——Job Number!

## 使用上面的jobs -l中的例子
fg       ## 这个切换到前台运行的程序将会是emacs——Why?

## 或者我们使用下面这种形式

fg %1    ## 切换到前台的将会是ping blog.useasp.net &>/dev/null &
## 此时你可以使用Ctrl+Z将其放回到后台,jobs查看之后你会发现,ping的最后没有了&了。
## 好神奇——想想为什么?

fg -     ## 这个是将-号那个程序切换到前台运行。
## 上述的例子中就是job number为1的程序 ping blog.useasp.net &>/dev/null &

有foreground,自然应该有background了,Yes,它的简写就是!相对应的,bg就是将程序切换到后台运行,注意:不仅切换到后台,更重要的是要在后台运行。Ctrl+Z只是把程序放入后台,但状态是停止。前面我们说过,我们可以将Ctrl+Z放入后台,并将已经停止的程序在后台运行的命令就是它了。来看看是怎么做到的吧:

ping blog.useasp.net &>/dev/null
## 这个将会占用Bash屏幕,因此我们在这里Ctrl+Z将它放入后台
## [2]+  Stopped                 ping blog.useasp.net &>/dev/null

jobs -l
## 此时我们使用jobs来查看,可以发现ping 这个程序已经是STOPPED了
## [1]-  Stopped                 emacs  (wd: ~)
## [2]+  Stopped                 ping blog.useasp.net &>/dev/null

## 让我们想办法让ping在后台继续运行
bg %2
## 此时ping将被放到后台运行
## [2]+ ping blog.useasp.net &>/dev/null &

jobs -l
## 查看下当前的状态:
## [1]+  Stopped                 emacs  (wd: ~)
## [2]-  Running                 ping blog.useasp.net &>/dev/null &
## 已经在后台运行了。

 到此为止,你基本上可以在下熟练的管理在Bash上程序了。当然,这些只是对程序的运行态进行管理,对程序本身并没有影响,那在实际操作中我们有一类操作是会影响程序本身的,比如:重启程序,关闭程序。而这类操作我们要使用的是另外一个命令:kill

命令能够通过信号来控制运行中的程序:

kill -SIGNAL %jobNumber
## -SIGNAL可以通过kill的-l(小写的L)参数列出本机能够支持的信号(SIGNAL)列表
## 常用的SIGNAL有:
## 信号值   信号名        描述
##   -2    SIGINT     终端产生的中断,Ctrl+C
##   -9    SIGKILL    强制关闭程序(KILL),直接杀死
##   -15   SIGTERM    退出程序运行(TERMINATION)
##                    这个和强制关闭不同,这个是程序正常退出的流程
## 如果不带SIGNAL,则默认是-15,以正常的方式退出程序

## 当然,我们更常用的可能是kill的另外一个用法
kill -SIGNAL PID
## 通过PID来kill程序
## 如果要一次性移除多个程序,也许你会想用:
killall ping

有了这些命令,我们就能将尽可能剥削系统的资源,而不至于让我们累个半死,系统闲的要死了。不会剥削系统资源的操作者不是好管理员!

 有了这些命令的时候,你也许很兴奋,终于,我们可以在我们不在系统上的时候,让系统能够为我们做事了,于是,愉快在bash上写上了无数以&结尾的命令,然后,妥妥的关闭了我们的远程连接——恭喜你,你被耍了!系统也是会偷懒的,谁叫你不好好监工呢,如果你不想自己监工,那么请一个吧:nohup

的作用就是让我们的程序在我们退出远程登录(登出系统)的时候,能够不受到影响而继续执行,不过要注意,nohup并不直接支持Bash内建的命令,请使用Shell脚本将命令放在文件中,而后使用nohup执行你的Shell脚本,这才能稳稳的保证系统不偷懒!

nohup Command [parameters] &
## 将程序用nohup在后台运行
## Command是我们的Shell脚本或是非bash内建命令
## parameters非必须,是传递给Command的参数
## &放到后台运行
## 使用nohup运行的命令,会自动的将所有的输出重定向到当前用户的根目录下面的nohup.out文件

 当然,除了nohup,你也可以使用其他的命令来达到同样的目的,比如下面这些都可以

  1. at:不过at需要先启用,这个就是Windows下的计划任务嘛。具体的这里不展开了,又可以写上很多,有兴趣可以参考at的文档;
  2. setsidsetsid command,该命令使我们的命令的父进程是init,而不是当前Bash,只有关机,该程序才会退出;
  3. (command &):这个和上面的类似,也是将父进程设置为了init;
  4. disown:我们使用&来让程序在后台运行,之后我们可以根据该程序的Job Number,使用disown -h %job_number来将程序不受HANGUP信号影响;

举栗子总是更容易让人明白:

setsid ping blog.useasp.net &>/dev/null
## 让ping运行在一个新的会话当中,当然,会话的用户还是当前用户

(ping blog.useasp.net &>/dev/null &)
## 同上

ping blog.useasp.net &>/dev/null &
## 返回:
## [1] 24074
disown -h %1
## 脱离当前用户的信号控制
## disown后查看父进程,还是能看到ping是挂在当前bash
## 但重登录之后,就可以发现ping的父进程是init

 如果你要查看进程关系,可以试试pstree

OK,打完收工

Eclipse启动找不到JRE报错的解决方法

MitchellChu 2014-06-17 其他技术

今天下载了后发现居然运行不起来,报错说是在当前的(Eclipse根目录下)jre/bin/找不到javaw.exe,无法运行。但我明显就装了JRE啊。当然了,本人没有配JAVA_HOME变量。

启动运行报错的几种解决方法:

1. 既然说是在这个目录下找不到,那么就把我安装的jre目录直接拷贝到当前文件夹下。

2. 老老实实的在环境变量中配置JAVA_HOME变量

3. 最简单的就是直接修改Eclipse下的配置文件eclipse.ini,在其中加入(我是第一行了):

-vm
d:\Program Files (x86)\Java\jre7\bin\javaw.exe

无论怎么样,再次启动运行,它就老实了。

注意:使用的Eclipse版本必须要和JRE相对应,64位的jre匹配64位的Eclipse,否则。你猜我使用的是啥版本的?

感叹号提高Bash下效率——历史扩展(bang命令)

MitchellChu 2014-06-03 Unix & Linux 编程语言

前一篇中介绍了在Bash下用快捷键来提高工作效率,而在Bash下要高效的工作,不仅仅可以从快捷键的方式来达到,Bash下还有很多其他方式,比如,使用别名,在之前的使用一些Shell下的特殊符号等,都能够一定程度的简化操作。而在Bash下还有另外一类——历史扩展,如果应用的当也能很大程度提高操作效率,嗯!下你要放这么些代码,也显得很酷!

又被称为Bang(!)命令1,历史扩展是bash将历史命令转换到可执行命令的过程。Bash下的History库提供了一个与csh下历史扩展类似的历史扩展功能。历史扩展中操作历史命令一般有两个部分:

  1. 首先要从历史命令中找出相对应的命令,被选择到的命令我们称作为Event(条目),比如上面的,就是选择最后一条命令;
  2. 选择选定行的部分或全部文本以包含到当前行中。要操作的条目(Event)Bash将其拆分成了Words(词),命令中的Words是靠空格来分割的,我们就可以使用修饰符(Modifiers)来调整Words以符合我们的要求。注意:Words并不是英文单词,而是一个字符序列而已。

例子:

cat /tmp/cat.cat.txt
##这个是cat出cat.cat.txt的内容
!:0 !*:gs/cat./echo.
##获取命令,参数中的cat.换成echo.
##变成/tmp/echo.echo.txt内容.
## 第二个命令中:
##我们首先是选出命令!!(!:0可以写成!!:0,!*同样可以写成!!*)
##有了命令之后我们选择第二步
##利用0,选择出词(!:0选择出来的是cat)
##第三步是对词进行操作,这里是!*后面对参数进行了字符替换。
##最后变成完成的命令了:
## cat /tmp/echo.echo.txt
条目标志符(Event Designators)
条目标志符是一个到历史列表内一个命令行实体的引用,除非是绝对引用,不然条目的引用是相对历史列表中当前位置的。
条目标志符 条目标志符说明
! 开始一个历史替换,除非后面紧跟的是空格,制表符,行结束符,"=","("(当使用内建命令shopt开启了extglob的shell选项)。
!n 重复历史中编号为n的命令——历史编号可以参看history命令.
!-n 执行之前的第n条命令,执行上一条命令可以使用!!或者!-1,执行之前第三条命令:!-3,倒推的列表是history
!! 执行上一条命令,和Ctl-P,!-1的作用一样。
!string 执行最近的以string字串开头的命令。这个命令的意思是重复以!后字串开头的最后一条命令,比如:!ca将重复以字符ca开头的最后一条命令,如cat ReadMe,(假设最近一条是这个命令,并且ReadMe后紧跟换行符)
!?string[?] 在历史列表中以当前位置开始向后查找(往回搜索)包含string字符串的最近一条命令,如果要查找的string字符串后面紧跟换行符,则string后面的这个问号可以省略。例如:!?Read?还是会匹配cat ReadMe。(同上的环境),如果后面是换行符如:!?ReadMe,则不用输入结尾的[?]。
^a^b 快速替换,把上一条命令中的a替换成b,并执行替换后的命令。^a^b^类似。注意:这里只是替换一个找到的实例,相当于:!!:s/a/b
^abc 删除上一条命令中的abc。
!# 引用目前输入的所有字串,如:more a !#;这个最终的命令是more a more a
词标志符(Word Designators)
词标志符被用来在条目里面选择需要的词。一般用":"分隔条目指示符和词指示符。当词指示符是以"^","$","*","-","%"开头时,也可能会省略":"。词是从一行的行首开始,第一个词编号为0.插入到当前行中时,这些词使用单个空格分隔。
词标志符 词标志符说明
0 第0个词,在很多应用程序中,这就是命令本身。
n 第n个词
^ 第一个参数;也就是第一个词。
$ 最后一个参数。
% 最近"?string?"匹配的词。
x-y 词的范围:如果是'0-y'可以简写成'-y'.
* 除了第0个以外的所有词,这个和'1-$'同义,如果条目中只有一个词,使用'*'也不会返回错误,仅是返回一个空字符串而已。
x* 'x-$'的简写
x- 和x*类似,都是'x-$'的简写,不过需要注意,这个写法是忽略最后一个词的。

需要注意的是,在下使用词指示符的时候,可以没有条目指示符,如果没有使用条目指示符,则会把前一条命令作为词指示符的操作条目。

修饰符(Modifiers)
在可选的词指示符之后,你可以添加下面修饰符中的一个或多个,每个修饰符以':'开头。
修饰符 修饰符说明
h 去掉路径名的尾部,只保留头部。只移除最后一个'/'后面的内容,可以理解成是路径名的父目录。
t 去掉路径名部件中除尾部之外的所有内容。只保留最后一个'/'后的内容。
r 去掉尾部这样格式".suffix"的一个结尾后缀,保留基本名称。只删除最后一个点'.'后的内容。
e 仅保留后缀。仅保留最后一个点'.'及点后的内容。
p 打印新的命令但不执行。
q 引用替换的词,防止进一步替换。(译注,原文:Quote the substituted words, escapin further substitutions.——Mitchell Chu)。这个引用会直接对引用的命令加上单引号,防止进一步替换。开始这句不知道怎么翻译。后来Mitchell发现自己的这个翻译并没有错误,因为我们引用的词可能是个变量,这时候如果没有引号,就会引起进一步的替换,而是用此参数就能达到防止这种情况的发生。
x 这个和q一样,是引用替换的词,但是这个与q不同的地方在于,q是整体引用,而这个是会将替换的词使用空格,制表符,换行符来分割成一个个的词。
s/old/new/ 把条目行中找到的第一个old位置的内容替换成new位置的内容,'/'这个分隔符位置可以使用任何其他字符作为分隔符。如果要在old或new位置使用分隔符,需要使用反斜杆'\'来转义。如果'&'这个字符出现在new位置,将会被替换成old位置的内容,如果要使用'&'请用'\'转义。最后一个分隔符如果是整行的最后一个字符,则可以省略。
& 重复上次替换。这个是引用最后一次的s/old/new/内容。
g 见下,与a相同
a 使替换在整个条目中进行,和's'一起使用,例如:!!:gs/old/new/,或者和'&'一起使用。
G 对条目中的每一个词都执行一次其后的's'修饰符。这个方法在Bash 4.1.2下测试并不靠谱。
test $eee /tmp/test.log
echo !test:Gs/t/a/;
## 这个返回的test被替换两次
## 但后面的参数仅替换一次             
因此Mitchell在想,是不是仅对参数执行一次,而对命令(第0个词)进行全局替换。但另外一个测试,反驳了这个观点:
aaaaaaaaaaa $aaaaaaa /tmp/aaaaaaaaaaaaa.log
echo !aaaa:q:Gs/a/t/
## 此时,最多的替换出现在!:0,两次!
但多次测试结果来看,第零个词汇被替换最多两次,其他只替换一次。具体原因暂时未知!

 

说明:

1. !被称为Bang,而#!被称为Sha-Bang或Sh-Bang,因为#!是由Sharp(#)和Bang(!)组成,所以简称Sha-Bang。

 

参考:

1. 本文内容主要来源于GNU的Bash Reference Manual(Bash version 4.2)

Linux下更高效的使用Bash——快捷键

MitchellChu 2014-06-03 Unix & Linux 编程语言

在Linux下,Bash的地位无可忽视,日常中涉及到Linux下的管理与操作基本都是在Bash中进行,因此,为了提高Linux下工作效率,自然而然的就变成了如何高效使用Bash的问题。虽然上一篇Shell下的一些特殊字符在使用的时候,能够一定程度上提高效率,后一篇关于Bash下的历史扩展也能很大程度提高效率,但Bash上的一些快捷键才是提高效率的最简单也是最直接方式。本文正是奔着这个目标来的!

快捷键的一些说明:

  1. C = CTL = CTRL = CONTROL:这个键是指PC键盘上的Ctrl键
  2. M = ALT:这个键是PC键盘上的ALT键,如果你键盘上没有这个键,可以尝试使用ESC键代替
  3. S = SHIFT:此键是PC上的Shift键
  4. E = ESC:这个键是PC键盘上的ESC键,此键一般在键盘的左上角
  5. DEL = Backspace:此键是是PC键盘上的Backspace键,一般位于主键盘区的右上角
  6. 文中"[]"括住的为快捷键内容,"-"两边的内容是按住左边键,再按右边键获得,","逗号两边的内容是先按左边键,松开后再按右边键。如:[C-v]是表示按下Ctrl键之后,不要松开,再按下v键。
  7. 默认的情况下,的组成格式是:<Ctrl | Alt | Esc>-[Shift-]<char>。即由Ctrl,Alt,Esc之一开头,中划线,Shift,中划线,和一个字符组成。其中,中括号内的Shift和"-"有时可省略。
  8. 默认情况下,快捷键只有最后一个为字符,其他的键值均为功能键
  9. 出现[C-?]这类快捷键,由于"?"是需要使用SHIFT按键才能获得的字符,因此此类快捷键默认使用的是[C-S-?]

要注意,在里面,快捷键可能会被写成八进制或者十六进制的形式(跟在转义符后面); 脚本文件中的快捷键并不是总能起作用的。另外快捷键有个规律,Ctrl开头的快捷键一般是针对字符的,而Alt开头的快捷键一般是针对词的

Bash下,如果使用的是shell脚本文件,快捷键不一定是有的时候会出现同一个快捷键有不同的表现,这种情况一般是由于Bash所处的模式不同而引起的,你可以通过set命令来调整模式:

set -o emacs
##切到emacs模式
## set -o vi
##切到vi模式
## set -o
## 查看当前选项的设置状态

这个是Bash的option选项,你可以根据具体情况进行设置,本文使用的是emacs模式。

快捷键 快捷键说明
C-A 将光标移到行首(在命令行下)
C-B 退格 (非破坏性的),这个只是将光标位置往回移动一个位置。
C-C 中断. 终结一个前台作业.
C-D 从一个shell中退出 (类似于exit)."EOF" (文件结尾:end of file).它也用于表示标准输入(stdin)的结束.在控制台或xterm 窗口输入文本时, C-D删除在光标下的字符.如果没有字符存在,C-D 则会登录出该会话. 在一个xterm窗口中,则会产生关闭此窗口的效果。
C-E 将光标移动到行尾(命令行下)
C-F 将光标向前移动一个字符(命令行)
C-G BEL.在一些老式打印机终端上,这会引发一个响铃。在xterm终端上可能是哔的一声。
C-H 擦除(Rubout)(破坏性的退格)。在光标往回移动的时候,同时擦除光标前的一个字符。
#!/bin/bash
## 可以尝试下下面的代码
## C-H的表现也许和你想象的不一样
## 本例来自Advanced Bash-Scripting Guide
## 注意:因为中文原因,下面的^位置可能会出现漂移
a="^H^H"

echo "abcdef"
echo
echo -n "abcdef$a "       # abcd f
#  末尾有个空格     ^              ^  两次C-H的结果
echo
echo -n "abcdef$a"        # abcdef
#  末尾没有空格                        ^ 显示效果是没有按C-H?(为什么?).
                          # 这个结果和我们预期的不一致.
echo; echo

rubout="^H^H^H^H^H"       # 5个C-H.
## 来吧,让我们看看真相:
echo -n "12345678"
sleep 2
echo -n "$rubout"
sleep 2
## 现在,你知道真相了么?
C-I 水平制表符.
C-J 新行(换行[line feed]并到行首).在脚本中,也可能表示为八进制形式('\012')或十六进制形式('\x0a').
C-K 垂直制表符(Vertical tab.).在控制台或xterm 窗口输入文本时, C-K 会删除从光标所在处到行尾的所有字符。在脚本中,Ctrl-K可能会有不一样的行为,下面的例子给出其不一样的行为:
#!/bin/bash
## 一个C-K垂直制表符的例子

var=$'\x0aBottom Line\x0bTop line\x0a'
## 直接输出
echo "$var"
## 使用col来过滤控制字符
echo "$var" | col

## 上面的显示将会不一样

exit 0
C-L 跳纸,换页(Formfeed),清屏。清空终端屏幕。在终端上,这个命令的作用和clear命令一样。但当这个命令发送到打印机时,Ctrl-L会直接跳到纸张(Paper sheet)的末尾。
C-M 回车(Carriage return).
C-N 擦除从history缓冲区召回的一行文本(在命令行下)。如果当前输入是历史记录中选择的时候,这个是从这个历史记录开始,没按一次,是更接近的一条命令
C-O 产生一个新行(命令行)
C-P 从history缓冲区召回上一次的命令(命令行)。此快捷键召回的顺序是由近及远的召回,即按一次,召回的是前一次的命令,再按一次,是召回上一次之前的命令,这和C-N都是以当前的输入为起点,但是两个命令操作刚好相反,C-N是从起点开始由远及近(如果起点是历史命令的话)。
C-Q Resume (XON). 恢复/解冻,这个命令是恢复终端的stdin用的,可参见C-S
C-R 回溯搜索(Backwards search)history缓冲区内的文本(命令行),注意:按下之后,提示符会变成(reverse-i-search)'':输入的搜索内容出现在单引号内,同时冒号后面出现最近最匹配的历史命令
C-S Suspend(XOFF),挂起,这个是冻结终端的stdin。要恢复可以按C-Q。
C-T 交换光标位置与光标的前一个位置的字符内容(命令行)。比如:echo $var;,假设光标在a上,那么,按下C-T之后,v和a将会交换位置。
C-U 擦除从光标位置开始到行首的所有字符内容。在某些设置下,C-U会不以光标位置为参考而删除整行的输入。
C-V 在输入文本的时候,按下C-V之后,可以插入控制字符。比如:echo -e ‘\x0a';echo <C-V><C-J>;这两种效果一样。这点功能在文本编辑器内非常有效。
C-W 当在控制台或一个xterm窗口敲入文本时, C-W 会删除从在光标处往后(回)的第一个空白符之间的内容.在某些设置里, C-W 删除光标往后(回)到第一个非文字和数字之间的字符.
C-X 在某些文字处理程序中,这个控制字符将会剪切高亮的文本并且将它复制到剪贴板中。
C-Y 将之前已经清除的文本粘贴回来(主要针对C-U或C-W)。
C-Z 暂停一个前台的作业;在某些文本处理程序中也作为替换操作;在MSDOS文件系统中作为EOF(End-of-file)字符。
C-\ 退出。和C-C差不多,也可能dump一个"core"文件到你的工作目录下(这个文件可能对你没用)
C-/ 撤消操作,Undo。
C-_ 撤消操作
C-xx 在行首和光标两个位置间进行切换,此处是两个"x"字符
 
M-B 光标往回跳一个词,词以非字母为界(跳动到当前光标所在词的开头)。
M-F 光标往前跳一个词(移动到光标所在词的末尾)
M-D 删除光标所在位置到光标所在词的结尾位置的所有内容(如果光标是在词开头,则删除整个词)
M-Del Del是Backspace键,这个删除光标所在位置到词开头的所有内容。
M-C 将光标所在位置的字母转为大写(如果光标在一个词的起始位置或之前,则词首字母大写)
M-U 将光标所在位置到词尾的所有字母转为大写
M-L 将光标位置到词尾的所有字母转为小写
M-R 取消所有变更,并将当前行恢复到在历史记录中的原始状态(前提是当前命令是从历史记录中来的,如果是手动输入,则会清空行)。
M-T 当光标两侧都存在词的时候,交换光标两侧词的位置。如:abc <M-T>bcd -> bcd abc
M-. 使用前一次命令的最后一个词(命令本身也是一个词,参见后一篇的Bang命令中的词指示符概念)
M-_ 同M-.
M-No. M+数字,这个数字可以是正或者是负,这个键单独没有作用,必须后面再接其他内容,如果后面是字符,则表示重复次数,如:[M-10,k]则光标位置会插入10个k字符(负值在这种情况下无效);如果后面接的是命令,则数字会影响后面命令的执行结果,如:[M--10,C-D]则向C-D默认方向相反(负数)的方向执行10次操作。
M-< 移动到历史记录中的第一行命令。
M-> 移动到历史的最后一行,即当前正在输入的行(没有输入的情况下为空)
M-P 从当前行开始向前搜索,有必要则向"上"移动,移动时,使用非增量搜索查找用户提供的字符串。
M-N 从当前行开始向后搜索,如果有必要向"下"移动,移动时,使用非增量搜索查找用户提供的字符串。
M-C-Y 在标志点上插入前一个命令的第一个参数(一般是前一行的第二个词)。如果有参数n,则插入前一个命令的第n个词(前一行的词编号从0开始,见历史扩展)。负的参数将插入冲前一个命令的结尾开始的第n个词。参数n通过M-No.的方式传递,如:[M-0,M-C-Y]插入前一个命令的第0个词(命令本身).
M-Y 轮询到删除环,并复制新的顶端文本。只能在yank[C-Y]]或者yank-pop[M-Y]之后使用这个命令。
M-? 列出能够补全标志点前的条目
M-* 把possible-completions[M-?]命令能生成的所有文本条目插入到标志点前.
M-/ 试图对标志点前的文本进行文件名补全。[C-X,/]把标志点前的文本当成文件名并列出可以补全的条目。
M-~ 把标志点前的文本当成用户名并试图进行补全。[C-X,~]列出可以作为用户名补全标志点前的条目。
M-$ 把标志点前的文本当成Shell变量并试图进行补全。[C-X,$]列出可以作为变量补全标志点前的条目。
M-@ 把标志点前的文本当成主机名并试图进行补全。[C-X,@]列出可以作为主机补全标志点前的条目。
M-! 把标志点前的文本当成命令名并试图进行补全。进行命令名补全时会依次使用别名、保留字、Shell函数、shell内部命令,最后是可执行文件名。[C-X,!]把标志点前的文本当成命令名并列出可补全的条目。
M-TAB 把标志点前的文本与历史记录中的文本进行比较以寻找匹配的并试图进行补全。
M-{ 进行文件名补全,把可以补全的条目列表放在大括号之间,让shell可以使用。

 在Bash下,如果能够妥善的使用快捷键,在的操作会变得非常快捷,比如我们在使用cat创建一个文件时,我们可以使用快捷键[C-D]:

## 不用快捷键
cat >>/tmp/test<<_EOF
##这里是内容
##最后我们要在新行里面输入_EOF
##cat见到_EOF才会将内容写到文件中

##使用快捷键
cat >>/tmp/test
##这里输入内容
##输入完毕之后,直接[C-D]结束

 有的时候我们需要创建一个文件,而后对这个文件进行操作:

touch /tmp/a-test-file-from-blog.useasp.net

## 不使用快捷键,文件名要重新输入
chmod u+x /tmp/a-test-file-from-blog.useasp.net

##使用快捷键
chmod u+x <M-.>
## 快捷键[M-.]自动会将上面的最后一个参数附加

 怎么样,有没有更有效率?

当然,Bash的快捷键只有在不断的使用中,才能达到真正的高效,在开始连要用那个快捷键都要思考半天的情况下,高效是很难的——但磨刀不误砍材工,前期的投入是值得的。

如果你想自己的Bash有那么一些不同,你也可以自己自定义快捷键,使用bind命令即可,Bash中的快捷键其实是来提供的,因此,这里快捷键的设置其实就是配置Readline,Readline中分两种快捷键,一种是Readline内部的函数快捷键,另外一种是执行Shell命令,设置的时候稍有不同:

##查看Readline中可以使用的函数名称
bind -l
##查看当前绑定的案件配置与其对应的功能
bind -v
##已经绑定的快捷键
bind -p

##绑定自定义执行命令shell命令的快捷键
bind -x '"\C-x\C-l":ls -al'
## 绑定后,按[C-x,C-L]就能执行ls -al

## 绑定内置函数功能
bind "\C-x":backword-delte-char
##这个是这行Readline库中的函数backword-delte-char

 这种设置只是针对当前的会话有效,一旦会话丢失,这样设置的快捷键就会丢失,为了能够让设置的快捷键永久有效,我们就需要将快捷键的配置写入文件。在Linux系统中,能永久保存快捷键的地方有两个,全局和用户的配置文件,全局的是/etc/inputrc,而用户的是在用户的根目录下~/.inputrc,全局的会影响所有的用户,而用户根目录下的只会对相应的用户产生影响。的大概样子像下面这样:

## 本例来自CentOS6.4的默认配置文件
$if mode=emacs

# for linux console and RH/Debian xterm
"\e[1~": beginning-of-line
"\e[4~": end-of-line
# commented out keymappings for pgup/pgdown to reach begin/end of history
#"\e[5~": beginning-of-history
#"\e[6~": end-of-history
"\e[5~": history-search-backward
"\e[6~": history-search-forward
"\e[3~": delete-char
"\e[2~": quoted-insert
"\e[5C": forward-word
"\e[5D": backward-word
"\e[1;5C": forward-word
"\e[1;5D": backward-word

# for rxvt
"\e[8~": end-of-line
"\eOc": forward-word
"\eOd": backward-word

# for non RH/Debian xterm, can't hurt for RH/DEbian xterm
"\eOH": beginning-of-line
"\eOF": end-of-line

# for freebsd console
"\e[H": beginning-of-line
"\e[F": end-of-line
$endif

说明: 

  1. 在配置文件中,\C代表Ctrl,\M代表Alt,\e代表Escape[Esc],\\是反斜杆[\],\'是单引号,\"是双引号;
    \C-    control prefix
    \M-    meta prefix
    \e     an escape character
    \\     backslash
    \"     literal ", a double quote
    \’     literal ’, a single quote
  2. 如果要查看某一个功能键的字符序列可以通过[C-v]来实现,或者输入cat后回车,进入编辑中,直接按快捷键
  3. 配置文件中可能会使用八进制或者十六进制来表示字符。

如果我们针对常用的操作设置成适当的快捷键,也许以前需要巴拉巴拉敲上半天的命令,你一个快捷键就能搞定,这无疑将会大大的提高我们的工作效率!快捷键吧,骚年!

Linux下高效编写Shell——shell特殊字符汇总

MitchellChu 2014-06-02 Unix & Linux 编程语言

下无论如何都是要用到shell命令的,在Shell的实际使用中,有编程经验的很容易上手,但稍微有难度的是shell里面的那些个符号,各种特殊的符号在我们编写Shell脚本的时候如果能够用的好,往往能给我们起到事半功倍的效果,为此,特地将Shell里面的一些符号说明罗列成对照表的形式,以便快速的查找。看看你知道下表中哦你的哪些Shell符号呢?

Shell符号及各种解释

使用方法及说明
#

注释符号(Hashmark[Comments])

1.在shell文件的行首,作为include标记,#!/bin/bash;

2. 其他地方作为注释使用,在一行中,#后面的内容并不会被执行,除非;

3. 但是用单/双引号包围时,#作为#号字符本身,不具有注释作用。

; 作为多语句的分隔符(Command separator [semicolon])。多个语句要放在同一行的时候,可以使用分号分隔。注意,有时候分号需要转义。
;; 连续分号(Terminator [double semicolon])。在使用case选项的时候,作为每个选项的终结符。在Bash version 4+ 的时候,还可以使用[;;&], [;&]
.

点号(dot command [period])。

1. 相当于bash内建命令source,如:

#!/bin/bash
. data-file
#包含data-file;

2. 作为文件名的一部分,在文件名的开头,表示该文件为隐藏文件,ls一般不显示出来(ls -a 可以显示);

3. 作为目录名,一个点代表当前目录,两个点号代表上层目录(当前目录的父目录)。注意,两个以上的点不出现,除非你用引号(单/双)包围作为点号字符本身;

4. 正则表达式中,点号表示任意一个字符。

" 双引号(partial quoting [double quote])。部分引用。双引号包围的内容可以允许变量扩展,也允许转义字符的存在。如果字符串内出现双引号本身,需要转义,因此不一定双引号是成对的。
' 单引号(full quoting [single quote])。单引号括住的内容,被视为单一字符串,引号内的禁止变量扩展,所有字符均作为字符本身处理(除单引号本身之外),单引号必须成对出现。
,

逗号(comma operator [comma])。

1. 用在连接一连串的数学表达式中,这串数学表达式均被求值,但只有最后一个求值结果被返回。如:

#!/bin/bash
let t1=((a=5+1, b=7+2))
echo t1=$t1, a=$a, b=$b
## 这个$t1=$b;
2. 用于参数替代中,表示首字母小写,如果是两个逗号,则表示全部小写,注意,这个特性在bash version 4的时候被添加的。例子:
a="ATest"
echo ${a,}
echo ${a,,}
## 前面输出aTest,后面输出的是atest。
\

反斜线,反斜杆(escape [backslash])。

1. 放在特殊符号之前,转义特殊符号的作用,仅表示特殊符号本身,这在字符串中常用;

2. 放在一行指令的最末端,表示紧接着的回车无效(其实也就是转义了Enter),后继新行的输入仍然作为当前指令的一部分。

/

斜线,斜杆(Filename path separator [forward slash])。

1.作为路径的分隔符,路径中仅有一个斜杆表示根目录,以斜杆开头的路径表示从根目录开始的路径;

2.在作为运算符的时候,表示除法符号。如:

a=4/2
` 反引号,后引号(Command substitution[backquotes])。命令替换。这个引号包围的为命令,可以执行包围的命令,并将执行的结果赋值给变量。如:
a=`dirname '/tmp/x.log'` 
## 后面dirname返回的结果会赋值给a,
## 注意,此处Mitchell特地使用了反引号和单引号,注意区别。
:

冒号(null command [colon])。空命令,这个命令什么都不做,但是有返回值,返回值为0(即:true)。这个命令的作用非常奇妙。

1. 可做while死循环的条件;

2. 在if分支中作为占位符(即某一分支什么都不做的时候);

3. 放在必须要有两元操作的地方作为分隔符,如:

: ${username=`whoami`}

4. 在参数替换中为字符串变量赋值,在重定向操作(>)中,把一个文件长度截断为0(:>>这样用的时候,目标存在则什么都不做),这个只能在普通文件中使用,不能在管道,符号链接和其他特殊文件中使用;

5. 甚至你可以用来注释(#后的内容不会被检查,但:后的内容会被检查,如果有语句如果出现语法错误,则会报错);

6. 你也可以作为域分隔符,比如环境变量$PATH中,或者passwd中,都有冒号的作为域分隔符的存在;

7. 你也可以将冒号作为函数名,不过这个会将冒号的本来意义转变(如果你不小心作为函数名,你可以使用unset -f : 来取消function的定义)。

!

感叹号(reverse (or negate) [bang],[exclamation mark])。取反一个测试结果或退出状态。

1. 表示反逻辑,比如后面的!=,这个是表示不等于;

2. 表示取反,如:ls a[!0-9] #表示a后面不是紧接一个数字的文件;

3. 在不同的环境里面,感叹号也可以出现在间接变量引用里面;

4. 在命令行中,可以用于历史命令机制的调用,你可以试试!$,!#,或者!-3看看,不过要注意,这点特性不能在脚本文件里面使用(被禁用)。

*

星号(wildcard/arithmetic operator[asterisk])。

1. 作为匹配文件名扩展的一个通配符,能自动匹配给定目录下的每一个文件;

2. 正则表达式中可以作为字符限定符,表示其前面的匹配规则匹配任意次;

3. 算术运算中表示乘法。

** 双星号(double asterisk)。算术运算中表示求幂运算。
?

问号(test operator/wildcard[Question mark])。

1. 表示条件测试;

2. 在双括号内表示C风格的三元操作符((condition?true-result:false-result));

3. 参数替换表达式中用来测试一个变量是否设置了值;

4. 作为通配符,用于匹配文件名扩展特性中,用于匹配单个字符;

5. 正则表达式中,表示匹配其前面规则0次或者1次。

$

美元符号(Variable substitution[Dollar sign])。前面已经表示过一种意思。

1. 作为变量的前导符,用作变量替换,即引用一个变量的内容,比如:echo $PATH

2.在正则表达式中被定义为行末(End of line)。

${} 参数替换(Variable substitution)。请参考具体内容以获得的详细信息。
$‘...’ 引用内容展开,执行单引号内的转义内容(单引号原本是原样引用的),这种方式会将引号内的一个或者多个[\]转义后的八进制,十六进制值展开到ASCII或Unicode字符。
$*, $@ 位置参数,这个在使用脚本文件的时候,在传递参数的时候会用到。两者都能返回调用脚本文件的所有参数,但$*是将所有参数作为一个整体返回(字符串),而$@是将每个参数作为单元返回一个参数列表。注意,在使用的时候需要用双引号将$*,$@括住。这两个变量收$IFS的影响,如果在实作,要考虑其中的一些细节,更多请自行查阅参考位置参数(Positional Parameters)的相关信息。
$? 此变量值在使用的时候,返回的是最后一个命令、函数、或脚本的退出状态码值,如果没有错误则是0,如果为非0,则表示在此之前的最后一次执行有错误。
$$ 进程ID变量,这个变量保存了运行当前脚本的进程ID值。
()

圆括号(parentheses)。

1, 命令组(Command group)。由一组圆括号括起来的命令是命令组,命令组中的命令实在子shell(subshell)中执行。因为是在子shell内运行,因此在括号外面是没有办法获取括号内变量的值,但反过来,命令组内是可以获取到外面的值,这点有点像局部变量和全局变量的关系,在实作中,如果碰到要cd到子目录操作,并在操作完成后要返回到当前目录的时候,可以考虑使用subshell来处理;

2. 用于数组的初始化。

{xx,yy,zz,...} 花括号扩展(Brace Expansion)。 在命令中可以用这种扩展来扩展参数列表,命令将会依照列表中的括号分隔开的模式进行匹配扩展。注意的一点是,这花括号扩展中不能有空格存在,如果确实有必要空格,则必须被转义或者使用引号来引用。例子:
echo {a,b,c}-{\ d," e",' f'} 
{a..z} 在Bash version 3时添加了这种花括号扩展的扩展,可以使用{A..Z}表示A-Z的所有字符列表,这种方式的扩展Mitchell测试了一下,好像仅适用于A-Z,a-z,还有数字{minNo..maxNo}的这种方式扩展。
{} 代码块(curly brackets)。这个是匿名函数,但是又与函数不同,在代码块里面的变量在代码块后面仍能访问。注意:花括号内侧需要有空格与语句分隔。另外,在xargs -i中的话,还可以作为文本的占位符,用以标记输出文本的位置。
{} \; 这个{}是表示路径名,这个并不是shell内建的,现在接触到的情况看,好像只用在find命令里。注意后面的分号,这个是结束find命令中-exec选项的命令序列,在实际使用的时候,要转义一下以免被shell理解错误。
[]

中括号(brackets)。

1. 测试的表示,Shell会测试在[]内的表达式,需要注意的是,[]是Shell内建的测试的一部分,而非使用外部命令/usr/bin/test的链接;

2. 在数组的上下文中,表示数组元素,方括号内填上数组元素的位置就能获得对应位置的内容,如:

Array[1]=xxx
echo ${Array[1]};
3. 表示字符集的范围,在正表达式中,方括号表示该位置可以匹配的字符集范围。
[[]] 双中括号(double brackets)。这个结构也是测试,测试[[]]之中的表达式(Shell的关键字)。这个比单中括号更能防止脚本里面的逻辑错误,比如:&&,||,<,>操作符能在一个[[]]里面测试通过,但是在[]却不能通过。[[]]里面没有文件名扩展(filename expansion)或是词分隔符(Word splitting),但是可以用参数扩展(Parameter expansion)和命令替换(command substitution)。不用文件名通配符和像空白这样的分隔符。注意,这里面如果出现了八进制,十六进制等,shell会自动执行转换比较。
$[...] 词表达表示整数扩展(integer expansion),在方括号里面执行整数表达式。例:
a=3
b=7
echo $[$a+$b]
echo $[$a*$b]
##返回是10和21
(()) 双括号(double parentheses)。 表示整数扩展(integer expansion)。功能和上面的$[]差不多,但是需要注意的是,$[]是会返回里面表达式的值的,而(())只是执行,并不会返回值。两者执行后如果变量值发生变化,都会影响到后继代码的运行。可对变量赋值,可以对变量进行一目操作符操作,也可以是二目,三目操作符。
>,&<,>&,>>,<,<> 重定向(redirection)。
scriptname >filename
重定向scriptname的输出到文件filename中去,如果文件存在则覆盖;
command &>filename
,会重定向command的标准输出(stdout)和标准错误(stderr)到文件filename中;
command >&2 
把command的标准输出(stdout)重定向到标准错误(stderr)中;
scriptname >>filename
,吧scriptname的输出(同>)追加到文件filenmae中,如果文件不存在则创建。
[i]<>filename
打开filename这个文件用来读或者写,并且给文件指定i为它的文件描述符(file descriptor),文件不存在就会创建。
(command)>,<(command) 这是进程替换(Process Substitution)。使用的时候注意,括号和<,>之间是不能有空格的,否则报错。其作用有点类似通道,但和管道在用法上又有些不同,管道是作为子进程的方式来运行的,这个命令会在/dev/fd/下面产生类似/dev/fd/63,/dev/fd/62这类临时文件,用来传递数据。Mitchell个人猜测之所以用这种方法来传递,是因为前后两个不属于同一个进程,因此需要用共享文件的方式来传递资料(这么说其实管道也应该有同样的文件?)。网上有人说这个只是共享文件而已,但是经过测试,发现虽然有/dev/fd/63这样的文件产生,但是这个文件其实是指向pipe:[43434]这样的通道的链接。
<< 双小于号(here-document[double less then marks])。这个也被称为Here-document,用来将后继的内容重定向到左侧命令的stdin中。<<可以节省格式化时间,别且使命令执行的处理更容易。在实作的时候只需要输入<<和终止标志符,而后(一般是回车后)你就可以输入任何内容,只要在最后的新行中输入终止标志符,即可完成数据的导入。使用here-document的时候,你可以保留空格,换行等。如果要让shell脚本更整洁一点,可以在<<和终止符之间放上一个连字符(-)。
<<< 三个小于号(here-strings)。Here-字串和Here-document类似,here-strings语法:command [args] <<<["]$word["];$word会展开并作为command的stdin。
<,> 小于,大于号(ASCII Comparison)。ASCII比较,进行的是变量的ASCII比较,字串?数字?呃...这个...不就是ASCII比较么?
\<...\> 词界符(word boundary)。这个是用在正则表达式中的一个特殊分隔符,用来标记单词的分界。比如:the会匹配there,another,them等等,如果仅仅要匹配the,就可以使用这个词界符,\<the\>就只能匹配the了。
| 管道(pipe)。管道是Linux,Unix都有的概念,是非常基础,也是非常重要的一个概念。它的作用是将管道前(左边)的命令产生的输出(stdout)作为管道后(右边)的命令的输入(stdin)。如:ls | wc l,使用管道就可以将命令连接在一起。注意:管道是每一个进程的标准输出都会作为下一个命令的标准输入,期间的标准输出不能跨越管道作为后继命令的标准输入,如:
cat filename | ls -al | sort
##想想这个的输出? 同时,管道是以子进程来运行的,所以管道并不能引起变量改变。
>| 强制重定向(force redirection)。这会强制重写已经存在的文件。
& 与号(Run job in background[ampersand])。如果命令后面跟上一个&符号,这个命令将会在后台运行。有的时候,脚本中在一条在后台运行的命令可能会引起脚本挂起,等待输入,出现这种情况可以在原有的脚本后面使用wait命令来修复。
&&,|| 逻辑操作符(logical operator)。在测试结构中,可以用这两个操作符来进行连接两个逻辑值。||是当测试条件有一个为真时返回0(真),全假为假;&&是当测试条件两个都为真时返回真(0),有假为假。
- 减号,连字符(Hyphen/minus/dash)。 1. 作为选项,前缀[option, prefix]使用。用于命令或者过滤器的选项标志;操作符的前缀。如:
## COMMAND -[选项列表] 
ls -al
sort -dfu $file
set -- $variable

if [ $file -ot $file2 ]
then
    echo "$file is older than $file2."
fi
2. 用于stdin或者stdout的重定向的源或目的[dash].在tar没有bunzip2的程序补丁时,我们可以这样:
bunzip2 linux-2.6.13.tar.bz2 | tar xvf - 
##将前面解压的数据作为tar的标准输入
##(这里使用一个-表示)
注意:在实作的时候,如果文件名是以[-]开头的,那么在加上这个作为定向操作符的时候,可能会出错,此时应该为文件加上合适的前缀路径,以避免这种情况发生,同样的,在echo变量的时候,如果变量是以[-]开始,那么可能也会产生意想不到的结果,为了保险起见,可以使用双引号引用标量:
var="-n"
echo $var
## 试试看有什么输出?

还有,这种表示方法不是Bash内建的,要达到此点的这种效果,需要看你使用的软件是否支持这种操作;

3. 表示先前的工作目录(previous working directory),因此,如果你cd到其他目录下要放回前一个路径的时候,可以使用cd -来达到目的,其实,这里的[-]使用的是环境变量的$OLDPWD,注意:这里的[-]和前一点是不同的;

4. 减号或者负号,用在算术操作中。

=

等号(Equals)。

1. 赋值操作,给变量赋值,么有空格在等号两侧;

2. 在比较测试中作为比较符出现,这里要注意,如果在中括号中作为比较出现,需要有空格符在等号左右两侧。

+

加号(Plus)。

1. 算术操作符,表示加法;

2. 在正则表达式中,表示的是其前的这个匹配规则匹配最少一次;

3.在命令或过滤器中作为选项标记,在某些命令或者内置命令中使用+来启用某些选项,使用-来禁止;

4. 在参数替换(parameter substitution)中,+前缀表示替代值(当变量为空的时候,使用+后面的值)

%

百分号(modulo[percent sign])。

1.在算术运算中,这个是求模操作符,即两个数进行除法运算后的余数;

2. 在参数替换(parameter substitution)中,可以作为模式匹配。例子:

p=b*9
var="abcd12345abc479"
echo ${var%p}, ${var%%p}
##从右边开始查找(想想从左是那个符号?)
##任何在b和9之间的内容(含)
##第一个是找到最短的符合匹配项
##后一个是找最大符合的匹配项(贪婪匹配?)
~ 波浪号(Home directory[tilde]),这个和内部变量$HOME是一样的。默认表示当前用户的家目录(主目录),这个和~/效果一致,如果波浪号后面跟用户名,表示是该用户的家目录,
~+ 当前的工作目录(current working directory)。这个和内置变量$PWD一样。
~- 前一个工作目录(previous working directory)。这个和内部变量$OLDPWD一致,之前的[-]也一样。
=~ Bash 版本3中有介绍,这个是正则表达式匹配。可用在[[]]测试中,比如:
var="this is a test message."
[[ "$var" =~ tf*message ]] && echo "Sir. Found that." || echo "Sorry Sir. No match be found."
##你可以修改中间的正则表达式匹配项,正则表达式可以但不一定需要使用双引号括起来。
^

脱字符(caret)。

1. 在正则表达式中,作为一行的行首(beginning-of-line)位置标志符;

2. 在参数替换(Parameter substitution)中,这个用法有两种,一个脱字符(${var^}),或两个(${var^^}),分别表示第一个字母大写,全部大写的意思(Bash version >=4)。

空白 空白符(Whitespace)。空白符不仅仅是指空格(spaces),还包括制表符(tabs),空行(blank lines),或者这几种的组合。可用做函数的分隔符,分隔命令或变量,空行不会影响脚本的行为,因此可以用它来规划脚本代码,以增加可读性,在内置的特殊变量$IFS可以用来针对某些命令进行输入的参数进行分割,其默认就是空白符。在字符串或变量中如果有空白符,可以使用引号来规避可能的错误。

怎样,你有多少是了解的呢?Mitchell在开始的时候,发现在这里面有好多都是不认识呢。

说明:

因为涉及到翻译,文中内容不一定完全翻译准确,如果你发现有错误的地方,还请包涵指正。

参考:

  1. 本文主要内容来源:Advanced Bash-Scripting Guide
  2. 对话 UNIX: !$#@*%
  3. wikipedia的Here文档

参考内容为本篇成文之际给予帮助较大的文章,在整个过程中还有很多网站信息给我提供了帮助,在此对他们的作者的无私贡献表示感谢!

关于博主

  一枚成分复杂的网络IT分子,属于互联网行业分类中的杂牌军。