wow按SHTFTwow左键不能捡东西西怎么办

灵异的shell
灵异的shell
我06年开始接触shell编程, 一开始照着别人的例子写些简单的脚本,
后来在网上找些shell语法的教程来看看(我想大多数同学学习shell也是这么个过程), 觉得shell挺简单的,
比其他语言简单多了. 但是随着写shell脚本次数的增多, 发现根本不是那么回事, 觉得shell太灵异了, 经常出现一些奇怪的错误,
#!/usr/bin/env bash
action = "$1"
echo "You want $action"
把上面的代码保存为test.sh并加上可执行权限, 执行./test.sh exit, 得到这样的错误提示:
./test.sh: line 3: action: command not found
#!/usr/bin/env bash
action= "$1"
echo "You want $action"
不错, 好像没错误了, 不过怎么啥都不打印啦?
有过其他语言编程经验的同学可能也会像我犯那样的错误, 同时会产生这样的疑问: 怎么shell中赋个值还这么多麻烦啊?
判断2个字符串是否相等
if [ $user = "admin" ]; then
echo "You are admin!"
上述代码判断一个用户是否为管理员, 但是有时候上面的代码运行时会出现这样的错误:
-bash: [: =: unary operator expected
这意思好像是说"期待一元运算符"? 啥意思?
有的教程里指出这样就可以了:
if [ x$user = "xadmin" ]; then
echo "You are admin!"
我试了下, 好像还真行, 为啥这样就可以呢? 这个”x”这么神奇? 其他的字母也可以这么神奇吗?
我看有的人这样写:
if [ "x$user" = "xadmin" ]; then
还有人这样写:
if [ x$user = xadmin ]; then
甚至有人这样:
if [ x$user = x"admin" ]; then
后来我无意中发现这样就可以了:
if [ "$user" = "admin" ]; then
这加不加双引号和加在哪到底有什么不同?
read好使不
echo str | read a, 怎么$a就不是我想要的str呢?
假如文件a的第一行是”str1 TAB str2&P, 执行:
read str & a
怎么输出是”str1 str2&P, 而不是”str1 TAB str2&P呢, 我的TAB哪去了?
神奇的注释
有人说下面这些符号可以用来注释shell:
: && COMMENT
: && COMMENT
echo "mm said, you could not touch me!"
好像还真行, 但是下面这个怎么不行呢?
: && COMMENT
result=$(grep str $file)
echo "mm said, you can touch me!"
还有其他的神奇注释吗?
其实类似上面这些灵异的例子还有很多, 但是纵观那些shell教程, 很少有能把shell的这些灵异的地方给读者讲明白的. 下面,
我结合我自己的一些经验, 力图把shell的一些本质语法给大家讲明白, 让大家在遇到一些灵异的问题时,
能迅速的定位和解决问题.
2 语法介绍
单词 (word)
一串字符构成一个单词, 也叫token
name (identifier)
仅有字母、数字、下划线构成, 而且由字母或者下划线开头的word叫name, 也叫标识符(identifier)
元字符 (metacharacter)
| & ; ( ) & & space tab
这些字符没有被引号引起来时, 可以用来分割单词
command | command2
command |& command2
把command的输出通过管道连接到command2的输入, |&连标准错误也一起做为command2的输入.
这里要注意的时, command2是在子shell里面执行的,
command2对环境所做的改变不会影响到command所在的shell环境. 这就解释了本文开头的问题3.1
引用用来去掉某些字符的特殊意义. 比如想使用元字符的字面意义必须对其进行引用.
引用有3类: 反斜线引用(\)、单引号引用、双引号引用.
单引号引用屏蔽单引号内的任何字符所具有的特殊意义, 包括反斜线(\), 所以单引号引用不能再包含单引号(比较杯具…)
双引号引用中除了 $ 、 ` 、 \ 、 ! ,
其他特殊字符的意义都被屏蔽.
$’string’
这个语法的意思是: string中含有的反斜线及其后的字符会被特殊解释, 比如: \t会被解释成TAB. 这个非常有用,
比如sort的字段分隔符只能是单个字符, 如果想用TAB做字段分隔符的话, 好多人都这样: sort -t ” “,
由于好多编辑器会把TAB变成4个空格, 所以这样做经常会出问题, 那现在你可以这样了: sort -t $’\t’
(PARAMETERS)
参数是用来存储值的实体, 它可以是数字(0, 1, 2 …)、name、某些特殊字符(@, *, …).
当参数是一个name时, 也叫变量(variable), 变量赋值:
name=[value]
等号2边不能有空格, 如果有空格的话, shell解释程序怎么知道你到底是想要运行name命令还是给name赋值呢?
所以的shell的变量赋值才不得不这样”讲究”
shell变量也可以 +=
在命令之前的变量赋值语句只影响该命令, 比如:
LANG= sort file
上面的命令表示在运行sort file的时候LANG为空, 不会影响其他的后续命令. 你是否还记得这样的代码:
tmp_LANG=$LANG
LANG=zh_CN
LANG=$tmp_LANG
位置参数 (Positional Parameters)
$0, $1, …
怎么重设位置参数? 用set
$10可以吗? 用${10}
特殊参数 (Special Parameters)
$* == $1 $2 $3 ...
"$*" == "$1c$2c$3...", c为IFS的第一个字符
"$@" == "$1" "$2" "$3" ...
$* 和 $@ 啥区别? 见后文
shell内置变量 (Shell Variables)
Internal Field Separator, 用来扩展后分割单词, read命令也是用它来分割单词. 默认值为:
这个变量控制你的环境所使用的语言(locale), 还有LC_开头的好几个shell变量也控制locale相关的一些方面.
当你sort一个含有中文的文件时, 是不是结果不如你所愿? 试试LANG=C sort
可执行文件的搜索路径
(EXPANSION)
命令行被分割成单词后, 开始执行扩展. 扩展有大括号扩展(brace expansion), 波浪号扩展(tilde
expansion), 参数和变量扩展(parameter and variable expansion),
算术扩展(arithmetic expansion), 命令替换(command substitution), 单词分割(word
splitting), 路径扩展(pathname expansion). 扩展的优先级也如上所示.
有的系统还支持进程替换(process substitution)
大括号扩展
echo a{b,c}
echo {1..10}
1 2 3 4 5 6 7 8 9 10
echo {10..1}
10 9 8 7 6 5 4 3 2 1
echo {1..10..3}
echo {a..f}
a b c d e f
echo {a..f..2}
波浪号扩展
echo ~/sdfa
/home/taoshanwen/sdfa
~- =& OLDPWD
${parameter}, 就是取出parameter的值, 有很多形式:
${parameter:offset}
${parameter:offset:length}
对parameter进行substr
${parameter#word}
${parameter##word}
删掉匹配的前缀
${parameter%word}
${parameter%%word}
删掉匹配的后缀
还有很多, 详见bash man
$(command) 或者`command`, 把command的输出做为结果
$((expression)), 对expression进行算术表达式操作, 例如:
echo $((9 + 8 * 9))
echo $((9 + 8 ** 9))
假如我现在想比较两个目录dir1和dir2中的文件有啥不同, 我想很多人会这样做:
ls dir1 & 1
ls dir2 & 2
但你试试这样:
diff &(ls dir1) &(ls dir2)
是不是也可以? 很神奇吧. 上面的这个语法&(command)就是进程替换.
&(command)表示把command的输出生成一个临时文件, 并把这个文件名作为另外一个命令的参数. 对于上面的命令,
就是把”ls dir1&P命令的输出生成一个临时文件, 并把临时文件名做为diff命令的第一个参数. 再举一个例子:
wget -q -O &(cat)
wget命令会把下载后的文件保存到文件中去, 但是我们可以用上面的命令不让它保存到文件中去, 而是显示出来.
wget的”-O”选项后本来应该是一个文件名的参数, 但是我们现在用&(cat)代替,
表示wget下载下来的内容放到一个临时文件中, 然后把这个临时文件名再传给&()里面的cat命令.
灵活运用进程替换, 将会非常的方便, 严重推荐
shell解释器最为重要的一步! shell灵异的来源
上述扩展如果没有双引号扩起来, 扩展完后, shell将会对结果用IFS进行单词分割. 例如:
echo "$str"
为什么加不加双引号结果会迥然不同? 因为没加双引号时, shell会对扩展结果进行单词分割, $str的扩展结果为”a b
c”, 分割后变成3个单词a、b、c, 这3个单词做为echo命令的三个参数, 最终输出结果自然是”a b c”了.
想起来本文开头的3.2问题了吗? 知道怎么回事了吧?
另外, 扩展结果为空的话, 如果没有被双引号或者单引号扩起来的话, 会被删掉. 例如:
#!/usr/bin/env bash
mysql -u $user db -e "$sql"
上面这个脚本如果第一个参数为空的话, $user将会被删掉, 从而mysql的用户名会变成db, 正确的代码应该是:
mysql -u "$user" db -e "$sql"
那你知道下面这些代码的错误之处了吗?
str=$(cat file)
for line in "$str"; do
echo "$line"
说到这里, 我们来说说$*和$@的差别. 它们在不加双引号时完全一样, 但是不加双引号时, 他们都有一个问题,
就是扩展会进行单词分割, 如果输入的参数中含有空格, 可能有时候结果就不是我们想要的了, 比如:
#!/usr/bin/env bash
for i in $*; do
保存上述的程序为test.sh, 该程序想打印每个输入参数,
taoshanwen@taoshanwen-laptop ~$ ./test.sh ab cd ef
taoshanwen@taoshanwen-laptop ~$ ./test.sh "ab xx" "cd yy" "ef zz"
上述结果并不是我们想要的, 那怎么取得准确的输入参数呢? “$@”可以解决, 你可以试试,
如果当前路径下有文件ab、ac、ad, 那么:
删除引用(Quote Removal)
经过上述扩展之后, 对于不是由于上述扩展产生的并且没有被引用的双引号、单引号、反斜线都会被删掉, 例如:
echo "xx" =& xx
echo a"xx" =& axx
经过上面这么多的了解, 我们大致知道了shell解释器的解释过程:
2.6 重定向
Here Documents
here-document
把here-document作为某个命令的标准输入. 例子:
grep a && EOF
如果word用双引号括住, delimiter就是word删除引用后的结果, here-document里面不进行任何扩展.
如果word没有用双引号括住, 那么here-document里面会进行参数替换、命令替换、算术扩展.
我们再来看看本文开头说的那个神奇的注释,
: && COMMENT
*”:”* 是一个shell内置命令, 它不干任何事情, 它的返回值为0. 这样就好理解了, 被注释的内容实际上是作为
: 的标准输入, 而这个命令啥事情都没干, 起到注释的作用了. 但是你现在知道为啥下面这个没起到注释作用了吗?
: && COMMENT
result=$(grep str $file)
echo "mm said, you can touch me!"
Here Strings
&&& here-strings
把word作为命令的标准输入, 例子:
grep a &&& abc
这个内置命令比which强大多了, 可以查找别名、函数、内置命令
taoshanwen@taoshanwen-laptop ~$ type ls
ls 是 `ls --color -N --show-control-chars' 的别名
ls 是 /bin/ls
taoshanwen@taoshanwen-laptop ~$ type [
[ 是 shell 内嵌
[ 是 /usr/bin/[
grep有个&color选项, 可以高亮匹配的地方, 非常不错
在你的.bashrc里面加入下面的代码:
# less color configure
export LESS_TERMCAP_mb=$'\E[01;34m'
export LESS_TERMCAP_md=$'\E[01;31m'
export LESS_TERMCAP_me=$'\E[01;35m'
export LESS_TERMCAP_se=$'\E[0m'
export LESS_TERMCAP_so=$'\E[01;44;33m'
export LESS_TERMCAP_ue=$'\E[01;36m'
export LESS_TERMCAP_us=$'\E[01;32m'
保证你的man会色彩缤纷, 重点突出, 非常方便
[[]]和[]的区别
[[]]内不进行单词分割和路径扩展, 所以
[]内则进行所有的扩展, [ $a = ab ]是不保险的.
[[]]内的&&是用当前locale做字符串比较的, []内的&&是根据ASCII顺序做比较的,
2者都不是对数字进行比较的, 这个需要注意, 比如可以试试 echo $?,
是不是返回0? 另外, [只是内置的命令, 所以不能直接[ 3 & 2 ], 这样的话, &是元字符, 当作重定向符号了,
需要对&进行转义, 需要这样 [ 3 "&" 2 ]
[[]]的==、!=、=~确实是正则匹配的, 具体用法可以见bash man
, shell里的日志工具,
和log4系列的其他日志库配置基本差不多
, shell的单元测试工具
, shell的调试工具
shell快捷键
6 shell炸弹
上面的命令能迅速的灭了你的系统, 慎用! ulimit -u进行限制
7 shell加密
, 简单的加密工具,
会把shell转换成一个二进制文件
, 更加强大的加密工具
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。魔兽高手来帮忙_百度知道WOW国服的未开放地点_百度知道

参考资料

 

随机推荐