C2 shell

家住魔仙堡 提交于 2020-04-01 01:04:31

 

1.什么是shell?

用户与内核之间的一个接口。最流行和常用的: bash。

2.重定向

> 重定向到另外的文件。0,1,2对一个程序来说是最常用的三个文件描述符!

>>是把内容附加到文件的尾部而不会覆盖文件原有的内容。

这命令啥意思?

#kill -HUP 1234 >kill.std 2>kill.stderr
#kill -l 1234 > kill.std 2>&1
第一条语句的解读:>kill.std等同于1>kill.std,标准输出1是默认的可以不写!
第二条语句的解读:将标准错误输出2绑定到标准输出1,然后将标准输出重定向到kill.std。
另外一个例子:
[chengmo@centos5 shell]$ ls test.sh test1.sh >/dev/null 2>&1
#将错误输出2 绑定给 正确输出 1,然后将 正确输出 发送给 /dev/null设备  这种常用
 
注意:

(1)shell遇到”>”操作符,会判断右边文件是否存在,如果存在就先删除,并且创建新文件。不存在直接创建。 无论左边命令执行是否成功。右边文件都会变为空。很霸道的地方!

(2)“>>”操作符,判断右边文件,如果不存在,先创建。以添加方式打开文件,会分配一个文件描述符[不特别指定,默认为1,2]然后,与左边的标准输出(1)或错误输出(2) 绑定。

(3)当命令执行完,绑定文件的描述符也自动失效。0,1,2又会空闲。

(4)一条命令在执行前,先会检查输出是否正确,如果输出设备错误,将不会进行命令执行。

 
3.管道
进程同时运行并且数据在他们之间自动协调的流动。
#ps -xo command|sort|uniq|grep -v sh|more

注意:

在一些列命令中不要使用名字相同的临时文件,因为这些文件是第一条命令被执行的时候就同时创建的,那么你只会得到一堆空白的文件。
例如:

#cat myfile.txt |more|sort>myfile.txt

你会得到一个空白的myfile.txt,因为在命令被创建的一瞬间,创建了新的空白的myfile.txt,覆盖了原本有内容的myfile.txt。

4.作为程序设计的shell

(1)交互式程序

 1 $ for file in *
 2 > do
 3 > if grep -l POSIX $file
 4 > then
 5 > more $file
 6 > fi
 7 > done
 8 posix
 9 This is file with POSIX in it - treat it well
10 $

期待进一步输入的时候,提示符变成了>,而何时输入完毕由shell判断。(咋判断?)

通配符扩展(globbing):*一个字符串,?一个字符,[set]方括号中的任意一个字符,那么[^set]是取反,既匹配任何没有出现在所给的字符集中的字符。而{}允许将任何的字符串组放在一个集合中。

eg:

$ ls my_{love,wife}.name

列出文件my_love.name和my_wife.name。注意,是和!

另:上面一段代码另外的方式:

1 $ more 'grep -l POSIX *'
2 
3 或:
4 $ more $(grep -l POSIX *)
5 
6 这两种是等效的,推荐后一种写法,前一种写法由于带有单引号,为了避免复杂的嵌套不推荐使用。
7 
8 $ grep -l POSIX * |more
9 输出有所含有POSIX字符串的文件名字,与上面的不同。

 

5.创建脚本和设置可执行

与交互式脚本不同的是创建可执行的脚本,这样不用每次都麻烦的输入。

 创建一个文件,编辑如下:
 1 #!/bin/bash
 2 #This is command
 3 
 4 for file in *
 5 do
 6     if grep -q POSIX $file
 7     then
 8     echo $file
 9     fi
10 done
11 
12 exit 0    

其中#!的作用该脚本被什么程序执行,而#的作用等同于C语言中的//。

脚本程序本质上与交互式的shell输入一样,所以在其中你可以引用能通过PATH环境变量引用到的所有的Linux命令!

默认返回0表示成功,这个自然不必多说。0总是最好滴。

利用$ chmod +x first.sh把脚本设置为可执行,当然 chmod 777 first.sh或者任何包含了一个“2”的XX都可以。与PATH=$PATH:.相比更推荐$./first的方法执行脚本,尽量不要随便在环境变量中增加新的目录。

如果你想把这个脚本拷贝到其他目录,并且把管理全乡交给root用户那么见如下的代码段。

1 $ cp first.sh /usr/local/bin
2 $ chown root /usr/local/bin/first.sh
3 $ chgrp root /usr/local/bin/first.sh
4 $ chmod 755 /usr/local/bin/first.sh
5 
6 另外可以
7 $ chmod u=rwx,go=rx /usr/local/bin/first.sh

 

6.shell的语法

(1)变量

任何一门程序设计语言首先要面对的问题就是变量,shell也不例外。

shell中的变量不用定义,就可以使用,而且默认的都是字符串形式的,如果要取值则在签名加上$符号。如果变量中含有空格,则应该用双引号将变量括起来。

 1 $ string=Hello
 2 $ echo $string
 3 Hello
 4 $ string="Hello world"
 5 $ echo $string
 6 Hello world
 7 $ string=3+3
 8 echo $string
 9 3+3
10 
11 一切都是字符串。
12 
13 
14 $ read string
15 Hi,there!
16 $ echo string
17 Hi,there!
18 
19 read用来读内容

shell变量中引号的使用需要注意下,一般情况,shell中的参数就用空白符分隔,那么如果变量中本来就包含空白符那怎么办呢呢,这时候需要把变量括在双引号中。当双引号、单引号、$、/遇到一起会发生什么。

 

 1 val = "I see"
 2 
 3 echo $var
 4 echo "$var"
 5 echo '$var'
 6 echo \$var
 7 
 8 echo Enter your val
 9 read val
10 
11 echo '$val' now become $val
12 exit 0

 

这段代码将会输出

I see

I see

$var

$var

I love

环境变量:

常用的环境变量有:$HOME  $PATH  $PS1 $PS2  $IFS  $0  $#  $$

$0:脚本的名字

$#:脚本的参数个数

$$:脚本的进程号,常用来生成临时文件,如/tmp/tmpfile_$$

常用的参数变量有:$1  $2  ...           $*        $@

$1 $2分别是脚本程序的第一个、第二个参数。 $* 、 $@其实很像,都是在一个变量中列出所有的参数列表,唯一的区别是就分隔各个参数的字符用什么,前者和IFS的第一个字符,而后者保证参数不会挤到一起。推荐用$@,保证更加清晰和明了。

实验

 

#!/bin/bash

val="Hi"
#等号两边没有空格,注意!
echo $val
echo $0
echo  "second para is $2"
echo  "first para is $1"
echo  "para list is $@"

exit 0

 

程序输出如下:

$./var aa bb cc

Hi

./var

second para is bb

first para is aa

para list is aa bb cc

 

(2)条件

test或者[命令:

if test -f fred
then
...
fi

或者

if [ -f fred ]
then
...
fi或者if [ -f fred ];then...fi

-n string(如果string不为空,则为真)和 -z string,-eq -ne -gt -ge -lt -le !都是什么意思,很简单,猜也猜的到。

-d file 如果文件为目录-e file(-f file) 如果文件存在-f file 如果文件是一个普通文件-r file 如果文件可写-s file 如果文件大小不为0-w file 可写-x file 可执行
 

(3)控制结构

if condition

then

  ,,,

else

  ,,,

fi

elif作进一步检查

注意:在引用变量的时候十分推荐用“$val”的方式,即加上双引号的方式。

for val in values
do
    statements
done

#!/bin/sh

for foo in bar fud 43
do
    echo "$foo"
done
exit 0

(a)for循环与通配符...

1 for file in $(ls f*.sh);do
2     lpr "$file"
3 done
4 exit 0

$(command)是一个知识点,后续会有更详细的介绍。

(b)while condition do

  statements

done

(c)until condition

do

  ...

done

until who | grep "$1" > /dev/null
do
    sleep 60
done

#循环反复执行,直到条件为真,也就是grep $1 返回真值

echo -e '\a'
echo $1 has just logged in

exit 0

(d)case

case val in 

  pattern [ | pattern] ...) statements;;

      pattern [ | pattern] ...) statements;;

esac

eg:

 1 #!/bin/bash
 2 
 3 echo "Is it morning,plz tell me."
 4 read awr
 5 
 6 case "$awr" in
 7     [yY]|[Yy][Ee][Ss] ) echo "Good morning";;
 8     [nN]|[Nn][Oo] )     echo "Good afternoon";;
 9     * )                 echo "Sorry,failed"
10 esac
11 
12 exit 0

 

为了避免过长,过复杂的条件判断和分支有了

(e)命令列表

这一样东西。

 AND :s1&&s2&&s3 形似与,主析取范式。计算方法也相似。

OR:   s1||s2||s3 形似或,主合取范式。

[ -f file ] && command for ture || command for false

作用类似C语言中的?:操作符。

 (4)函数

shell中传递函数的方法用$*,$1等。

(5)命令

.命令比较特殊,他使一个外部命令能够在当前的shell中执行,而不是子shell环境,这样该脚本就可以改变当前的环境。

eval是shell 的内置命令,考虑如下代码段:foo=10 x=foo y=‘$’$x echo $y 和foo=10 x=foo val y=‘$’$x echo $y   第一段代码输出$foo  第二段代码输出10!

export作用是导出变量,使在父脚本中定义的变量在子脚本中可见和可以使用,一旦导出,孙脚本都可以用,呵呵。

expr是表达式求值,例如x='expr $x + 1' 同样,单引号可以被$和()组合代替,即x=$(expr $x + 1)。在同样,expr可以替换为$(())。

set的作用是为当前的shell脚本设置环境变量,l例如:

1 #!/bin/bash
2 
3 echo "The date is $(date)"
4 set $(date)
5 #假定 date命令输出 2012 12 22
6 #那么set以后 该脚本的是$@就是:2012 12 22
7 echo "The month is $2"

shift左移参数,但是$0不会被覆盖,仅限于$1到无穷大,写个遍历参数的代码

1 while [ "$1"!=""];do
2     echo $1
3     shift
4 done

trap 命令 trap command signal,如此简单。command置为-表示以默认方式处理该信号,Linux中常用的信号就那么几个:HUP 1 挂起,INT 2 中断,QUIT 3 退出等等。

 find命令:

 eg:find / -name test -print #从根目录开始 搜索名字为test的文件 并把它打印出来。清晰 简单明了。

find命令的格式是:find [path] [option] [test] [action] ,路径部分很好理解,甚至可以同时指定多个目录。选项部分常用的有:-depth,-mount等。

测试部分MS是需要重点掌握的,-type c,-name pattern,-atime N,-mtime N,-newer otherfile,-user usrname 等等。!和-not,-a和-and,-o和-or是一样一样的。

注意在使用条件组合的时候需要括号来设置优先级,而括号在shell中又有特殊的含义,所以你必须用转移符号/来保证(和)不会被shell给处理了,eg:

find . /(-name "_*" -a -newer hahaha/) -type f -print  该命名的作用是在当前目录下查找名字以下划线开头并且比hahaha更新的 并且文件类型为普通文件,然后将它打印出来。

在find命令的最后加上-exec或者-ok你会感觉到这是神器,不过感觉有点像管道,但是又不一样好像。{}是魔术串,恩 魔术串,就是当前获取到的文件的全名,咋怎么踩刹车,\;。eg:

find .-name Iloveyou -type f -exec ls -al {} \:

 

grep命令:

find在文件系统中搜索文件,而grep在文件中搜索字符串,懂,亲?用exec将find的结果传递给grep,太棒了!

grep [options] PATTERN [FILES]  常用的选项:-c 输出数目,-E 启用扩展表达式,-h 取消每个输出行的普通前缀?? -i 忽略大小写 -l 只列出包含匹配行的文件名,而不输出真正的匹配行。-v 取反!(这个似乎常用!)


正则表达式:^ 表示行的开头,$表示行的结尾,.表示任意一个单个字符,[]表示一个匹配的范围。\提供了转义序列。其中[]还有很多特殊匹配模式。

eg:查找以字符e结尾的行

grep $e word.txt

eg:查找包含以字符a结尾的单词的行

grep a[[:blank:]] word.txt

eg:查找包含以TH开头的由3个字符组成的单词的行

grep TH.[[:blank:]] word.txt

eg:查找只有10个字符长并且全部由小写字母组成的单词的行

grep [[:blank:]][[:lower:]]\{10\} [[:blank:]] word.txt

可是说上说 grep -E [a-z]\{10\} word.txt

 

 

 

 

 

 

 

 

 

 

 

 
 
 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!