Shell编程与vim控制命令

Shell 编程

Linux命令

linux登录命令

    1. telnet远程网络登录:tlenethostip。此操作需要远程主机开启telnet服务端,一般为telnetd

    2. 通过ssh登录:

ssh -l username hostip

ssh username@hostip

scp –r username@hostip:/path/of/file local_path

命令帮助man

man命令可以查看命令或者函数的帮助文档,具体可以指定一个数字指定查找范围。如man3 printfman –kkeyword:可以按照keyword进行搜索

基本工具

  1. ls:显示文件名,ls–la; ls –lh可以看到Humanreadable的大小显示

  2. cat:显示文件内容

  3. rm:删除文件,rm–f强制删除,rm –r 删除目录

  4. less/more:分屏显示,man3 printf|more

  5. hostname:显示系统名,此系统名记录在/etc/hostname文件里面

  6. apropos:此命令在man的简短描述中搜索关键字。用于查找某个功能的命令。

  7. which/whereis:查找某个命令的执行体位置。

  8. locate:查找文件(比如动态库)所在位置

  9. who/finger:列出系统上的用户

  10. ps显示进程号,psaux|grep “minicom”查找minicom的进程号

  11. kill:给进程发信号。kill-9 1111,杀死进程号为1111的进程。kill还可以杀死真正运行的作业jobs,如kill%1,杀死一号作业,%号表示后面的数字为作业号。

  12. chmod:修改文件权限

    chmod –R u+x ./ #当前目录及其子目录的文件加执行权限。

  13. find:查找文件,一般和其他命令搭配使用。

find ./ -name “*.c”|wc –l #当前目录及其子目录下c文件的个数

文件操作

  1. cp:复制文件

  2. mv:移动文件,如果在同一目录下就表示重命名文件

  3. grep:查找字符串,如查找当前目录下所有c文件中printf的具体位置:

    find ./ -name “*.c” | xargs grep “printf”

  4. xargs:将标准输入按命令行格式解释

  5. head/tail:显示文件的头部/尾部。

  6. sort:按顺序显示文件。默认按照首字母排列。sort–n,按照字符串的大小升序排列。sort–r,翻转排列顺序。

  7. uniq:显示文件同cat,但是忽略文件中的重复行

  8. diff:比较两个文件,diff–y file1 file2,将两个文件并排显示,并指出两个文件的不同。diff–urN dir1/ dir2/递归比较两个目录的差异,形成patch文件

  9. file:获取文件信息

  10. echo:复制内容并回显。

  11. date:显示时间和日期

  12. script:记录会话

  13. unix2dos/dos2unix:将linux文件转换为windows格式。

  14. tar:归档文件管理。

tar –zcvf file.tgz file #file压缩成gzip格式的归档文件。

tar –zxvf file.tgz –C ~/ #file.tgz解压到用户目录下。

jcvfjxvfbzip2格式的创建和解压参数。

  1. mkdir:创建文件夹,mkdir–p ~/work/test/abc-p参数可以创建多层目录。

  2. ln:创建一个文件的链接,注意:默认为硬链接,硬链接为一个直接指向文件的指针,它和原文件(也是一个指向文件的指针)共享文件的inode,删除时,需要将所有的链接全部删除后,系统才会删除磁盘上的文件。软连接(符号链接)为指向硬链接的指针,创建时需加-s需用绝对路径名(相对路径名容易出错),比如

ln –s /usr/bin/vi /bin/vim #vi命令链接成为vim

这样输入vi的时候启动的是vim,它相当于一个快捷方式。

shell命令行

标准输入输出:

  1. shell将键盘作为标准输入,屏幕作为标准输出。

  2. 通过 >可以重定向输出, <重定向输入,比如

b cat #表示以a为输入,b文件输出执行cat命令

需要特别注意的是标准输出的定向文件会覆盖原来的文件,如果是>>在某个文件末尾追加输出。

管道

shell用管道将一个命令的输出直接连接到另一个命令的输入。符号:|。如

cat test.c | grep “printf”

管道可以很好的连接多个命令来完成一个功能。

teetee可以将一个输入输出到两个输出,如

who | teewho.out | grep root #将命令who的输出定位到who.out文件,同时作为grep的输入,查找root项。


在后台运行程序

将一个任务后台运行可以通过命令行加&符号

cat test.c | lpr & #后台打印test.c

bg:首先用CONTROL+Z将任务挂起,输入bg+%jobnum命令可以使任务在后台运行,如果只有一个任务被挂起,可不指定任务号。注意后台运行的程序标准输入和键盘断开,如果任务需要充键盘输入,则任务被阻塞。

fg:将某个后台运行的任务切换到前台运行,如果只有一个后台运行的任务,可以不指定任务号。

特殊字符

字符?:?表示单个字符匹配,注意的是?无法在文件名开头匹配句号“.”。如.cache就不能用?chache进行匹配。

字符*:字符*可以匹配0到任意多个连续的字符。如*abc,表示以abc结尾的所有文件

字符[]:[]表示与括号内的单独一个字符进行匹配。如[abc]*表示以a,b,c中任一字母开头的所有文件。字符号还可以跟!和^组合表示否定,如[^abc]*表示不以a,b,c中任一字符开头的所有文件。


任何shell命令都会在执行之前进行上述的shell展开,比如下面的命令可能无法找到所有的c文件

find –name *.c

因为*.c在命令执行之前,shell展开成当前目录的c文件,如果当前目录确实有.c文件,展开后命令格式出错,应该写成

find –name “*.c”



编辑器vim

vimlinux下面强大的编辑器。vim3种模式,普通模式,插入模式和命令模式。一开始为普通模式。按”:”冒号进入命令模式,按o,i,a进入插入模式。

下面就以写个test.c描述vim的使用。

vim的配置

vim强大之处在于它有很多很好用的插件。作为程序人员,首先要安装ctags

再安装vim的插件,taglistwinmanager。还有其他很多插件,不过我一般就只用这两个。

下面是我的vimrc

" All system-wide defaults areset in $VIMRUNTIME/debian.vim (usually just

"/usr/share/vim/vimcurrent/debian.vim) and sourced by the call to:runtime

" you can find below. If youwish to change any of those settings, you should

" do it in this file(/etc/vim/vimrc), since debian.vim will be overwritten

" everytime an upgrade of thevim packages is performed. It is recommended to

" make changes after sourcingdebian.vim since it alters the value of the

" 'compatible' option.


" This line should not beremoved as it ensures that various options are

" properly set to work with theVim-related packages available in Debian.

runtime! debian.vim


setfileencodings=utf-8,gb2312,gbk,gb18130,cp936

" Uncomment the next line tomake Vim more Vi-compatible

" NOTE: debian.vim sets'nocompatible'. Setting 'compatible' changes numerous

" options, so any other optionsshould be set AFTER setting 'compatible'.

set nocompatible


" Vim5 and later versionssupport syntax highlighting. Uncommenting the

" following enables syntaxhighlighting by default.

if has("syntax")

syntax on

endif


" If using a dark backgroundwithin the editing area and syntax highlighting

" turn on this option as well

"set background=dark


" Uncomment the following tohave Vim jump to the last position when

" reopening a file

if has("autocmd")

au BufReadPost * if line("'\"")> 1 && line("'\"") <= line("$")| exe "normal! g'\"" | endif

endif


" Uncomment the following tohave Vim load indentation rules and plugins

" according to the detectedfiletype.

if has("autocmd")

filetype plugin indent on

endif


" The following are commentedout as they cause vim to behave a lot

" differently from regular Vi.They are highly recommended though.

set showcmd " Show (partial)command in status line.

set showmatch " Show matchingbrackets.

set ignorecase " Do caseinsensitive matching

set smartcase " Do smart casematching

set incsearch " Incrementalsearch

set autowrite " Automaticallysave before commands like :next and :make

"set hidden "Hide buffers when they are abandoned

set mouse=a " Enable mouseusage (all modes)

" Source a global configurationfile if available

iffilereadable("/etc/vim/vimrc.local")

source /etc/vim/vimrc.local

endif

set nu

set foldmethod=syntax

set foldlevel=100

set autoindent

set smartindent

set tabstop=4

set shiftwidth=4

"TList

let Tlist_Show_One_File=1

let Tlist_Exit_OnlyWindow=1

nmap tl :Tlist

"Tlist

"winmannger

letg:winManagerWindowLayout='FileExplorer|TagList' "winmanagerTagList

nmap wm :WMToggle

"winmanager

注意的几点:

  1. filecoding,编码方式,里面设置可以支持中文,不然中文乱码

  2. setnocompatiable:不兼容老版本,不然键盘输入出问题(方向键变成了abcd

  3. set mouse=a:这句话让鼠标全局使能,可以使用鼠标

  4. set nu:显示行号

  5. setfoldmethod:设置折叠方式,普通模式下zc折叠代码,zo打开代码,在看大的代码块非常有用

  6. set autoindent:自动缩进

  7. tabstop=4:制表位宽度为4

  8. tl映射命令Tlist,需要安装taglist插件

  9. wm映射命令WMToggle,需安装winmanager

vim编辑

  • vim +filename就打开或者新建了一个文件

     然后按键盘i, 进入插入模式,输入代码。输入代码是可以使用ctrl+n/ctrl+p 进行自动补全(这个补全功能很弱,只是在本文件内部进行查找匹配)。然后wq 保存。

这里介绍下vim文本编辑的常用命令:

    1. nu,命令模式下输入行号可以直接跳到改行

    2. num+yy:普通模式当前光标所在向下复制num行,不加num表示复制本行,yw表示复制一个word

    3. num+dd:删除当前光标向下num行,如果不加num表示删除本行,dw表示删除一个workdG表示删除到末尾,d$删除到行尾。

    4. u:撤销修改

    5. p:粘贴最近复制的或者删除的内容

    6. qq在普通模式下表示记录操作。qa:表示记录操作到寄存器a,记录完成以q结束。然后按句点“。”重复寄存器里面的动作,也可以times@a将寄存器里的动作重复times次。

    7. 大面积注释:光标移到要注释的行首,CONTROL+V进入visual模式,下移光标到注释块最后一行行首,shift+i,输入//注释符号,按两次esc就可以看到这块代码被注释了。反注释时同样操作,将//删除就可以了。

    8. 格式化代码:vim提供num+=来格式化num行。或者使用visual模式选定需要格式化的区域,然后按=

    9. 查找字符:普通模式下“/“查找字符,”:%s“替换字符,如

%s/\/10/g

上命令表示将ten替换为10,:%s为替换开头。\<匹配字符串的左边界,\>匹配字符串的右边界,g表示全局范围。


这样就完成了一个文件的编辑。写个makefile编译这个文件。打开vim,在里面输入:make(vim支持make命令),如果编译出错,可以输入:cope,快速定位到错误所在

CONTROL+WW可以把光标在不同的窗口之间移动,编辑不同的窗口,输入ls可以看到当前vim有哪些缓冲器,即同时编辑的文件,输入buffer+缓冲区号可以将对应缓冲区切到前台编辑。

vim看代码

vim看大的项目工程我用的还不是很习惯,提供一些常用命令

  1. ctags –R *生成tags文件。这个命令需要在shell命令行下面敲,,在vim里面使用:!执行shell命令

  2. tags+=tagpath,把一个tagpathtags文件导入到当前的vim使用环境中。如tags+=./tags,表示把当前目录下的tags文件导入到vim中。

  3. tagtagname:打开tagname所在的文件,如果该tagname在多处出现,可以使用:ts,该命令列出每个tagname的具体位置,你可以选择正确的tag打开。

  4. gf:打开头文件。将光标移到头文件名上,按gf就可以打开该头文件,前提是该头文件在vimpath变量指定的路径内,如果没有,可以用setpath+=来增加搜索路径。

  5. gd在函数内所需光标下的单词第一次出现的位置,gD在文件范围内寻找光标下的单词第一次出现的位置,通常可以用来搜索的局部变量和全局变量

  6. #往回找光标当前的单词,*往后找光标当前的单词,配合hlsearch,可以很容一的找到函数中某个变量使用的地方,如果要清楚hlsearch,使用:setnohlsearch%可以在大括号之间跳转。

  7. CONTROL+]跳到变量/函数的定义,CONTROL+T调回上一步(和CONTROL+])对应。gctrl+]可以弹出选择列表

  8. CONTROL+i跳到前一步,CONTROL+o跳到后一步。

shell脚本编程

特殊符号变量

$#:表示输入的参数个数

$$:在脚本中表示进程号

$@$*:都表示命令行参数,$*把所有的参数当成一个参数,$@则生成一串参数。

$?:最近一条命令的退出状态

$!:后台运行的pid

$0:调用程序名称

$1-$n:命令行对应位置上的参数

[]:作用相当于test命令,[ command ]判断command执行结果的真值。[之后,]之前必须各有一个空格。

--:-- -v表示-v不是一个命令的参数,如cat–vcat -- -v

控制结构

  1. if...then

if [ $# -eq 0 ]

then

echo “argnum= 0”

elseif [ $# -eq1 ]

then

echo“argnum = 1”

else

echo “argnum= $#”

fi

test:测试后面条件的真值

eq(等于)/ne(不等于)/gt(大于)/ge(大于等于/lt(小于)/le(小于等于)

-d:文件是否存在并且是否为目录

-e:文件是否存在

-f:文件是否存在以及文件是否为普通文件(不是目录)

-r:文件是否存在以及文件是否可读

-s:文件是否存在以及文件是否大于0字节

-w:文件是否存在以及文件是否可写

-x:文件是否存在以及文件是否可执行

-a: AND运算

-o:OR运算

  1. for...in

for loop-index in argument-list

do

commands

done

注意for默认的$@可以传递带空格的参数,如下面的一个test.sh

#!/bin/sh

echo “$@”

for i

do

echo $i

done

for i in $@

do

echo $i

done


  1. while

    while test-command

    do

    commands

    done

  2. until

    until test-command

    do

    commands

    done

  3. breakcontinue

  4. case

case test-string in

pattern-1)

commands-1

;;

pattern-2)

commands-2

;;

esac

case结构中的匹配类型类似于一个模糊文件引用,可以匹配

*

匹配任一字符串,用作默认的case匹配

匹配单个字符

[...]

匹配括号内任一字符,可用两字符指定匹配范围,如[a-zA-Z]

|

case的分支可以满足多个条件,如A|B|C),patternA,B,C都可以进入这个分支

  1. select

#!/bin/bash

PS3="yourselect: "

selectchoice in apple peach orange QUIT

do

num=$REPLY

if[ $choice = QUIT ]

then

echo"thank you!"

break

fi

echo"your choice is $num:$choice!"

continue

done

select语句后选择的数字保存在键盘变量REPLY中,select是个循环语句,需要break或者exit退出。

文件描述符

打开文件描述符

exec n>outfile

exec m

复制文件描述符

exec n>&outfile

exec m<&outfile

关闭复制的文件描述符

exec n>&-

exec m<&-

数组

数组的声明:names=(element1element2 ...)

数组的引用:${names[index]}

下标[*][@]的作用是提取整个数组元素,但是:

A=(“${names[*]}”)表示把元素的内容合并复制给A,这样A只有一个元素

B=(“${names[@]}”)表示把元素复制个BBnames是一样的。

NAMES=(maxles)

A=("${NAMES[*]}")

B=("${NAMES[@]}")

declare-a

运行结果

${#names[*]}可以返回数组长度,用$(#names[index])可以返回对应下标的内容长度。

例子:

#!/bin/bash

PS3="yourselect: "

choiceArr=(applepeach orange QUIT)

echo"arrlen= " ${#choiceArr[*]}

echo"length of arr[0]: " ${#choiceArr[0]}

selectchoice in ${choiceArr[@]}

do

num=$REPLY

if[ $choice = QUIT ]

then

echo"thank you!"

break

fi

echo"your choice is $num:$choice!"

continue

done

执行结果:

变量局部性

export:脚本可以通过export声明导出变量的副本给其子进程使用。子进程对该变量的操作不影响父进程。

变量的初始化

:-符号不是使用默认值,如${name:-default}

:=表示设置默认值,${name:=default}

${name:?message}显示错误信息,判断变量是否为空或者未赋值,如果是,输出message并推出执行,返回码1

shell内置命令

trap:截获信号,如可以防止用户通过发送CONTROL+Z(信号数字18)来终止脚本运行。

stty:改变和打印终端设置。

tput:初始化终端或者查询终端信息。tputclear:清屏

basename:移除文件的路径和后缀名basename /home/test.sh .sh输出为test

set:用来初始化命令行参数变量,用于脚本的输入

unset:删除一个变量或者函数

read:接受用户输入,存在变量REPLY??中。read命令每次从标准输入中读入一行,并赋值给一个或者几个变量,read开始一一对应的赋值,最后一个变量接受所有剩下的参数。

exec:执行命令。注意exec执行命令不会返回返回到原来的脚本中,但是用exec重定位??会返回到原来的脚本。

execdate;echo “hello”,这个echo“hello”就不会执行,但是exec;echo “hello”中的后一句就会执行。

shift:将位置参数左移一位,如原来的$1就变成$0了。

kill:终止进程

getopt:分析命令行参数

表达式

  1. 算术表达式:算术表达式可以用let,但是带有空格的变量或者表达式必须用双引号“”,下面3中写法等价

    let “VALUE = VALUE * 10 + NEW”

    let VALUE=VALUE*10+NEW #表达式内部没有空格

    ((VALUE=VALUE * 10 + NEW))

  2. 逻辑表达式:逻辑表达式用[[expression]]来表示,同样的,[[之后和]]之前的空格是必须的。注意在shell的判读语句中,0表示真的状态,1表示状态为false:

#!/bin/bash

if [ $# -ne 2 ]; then

echo "Usage:./logicexp.sh num1 num2"

exit 1

fi

let "value1 = $1 +(12 + 3)*0"

let value2=$2+0

[[ $value1 == $value2 ]]

echo "the reslutof [[ $1==$2 ]]: " $?

[[ $value1 != $value2 ]]

echo "the reslut of [[ $1!=$2 ]]: " $?

执行结果:


逻辑表达式和测试语句式什么区别?

逻辑表达式比测试语句式多了字符串的比较



  1. 字符串模式匹配:

#

去除最小匹配前缀(从字符串头部匹配,删掉头部最小匹配字符串,所谓前缀)

##

去除最大前缀匹配(从字符串头部匹配,删掉头部最大匹配字符串)

%

去除最小匹配后缀(从字符串尾部匹配,删掉尾部最大匹配字符串,所谓后缀)

%%

去除最大匹配后缀(从字符串尾部匹配,删除尾部最大匹配字符串)

例子:

结果:

gawk模式处理语言

gawk [options] [program] [file-list]

gawk [options] –f program-file[file-list]

gawk中默认变量

 $0

当前记录(作为单个变量)

$1~$n

当前记录的字段

FILENAME

当前输入的文件名

FS

输入文件分隔字段

NF

当前记录的字段数目

NR

当前记录的记录编号

OFS

输出字段的分隔符(默认为空格符)

ORS

输出记录的分隔符(默认为换行符)

RS

输入记录分隔符(默认为换行符)


gawk默认从标准输入获取输入,可以用–f指定执行gawk程序,如

gawk –f testpasswd /etc/passwd

testpasswdgawk文件,从/etc/passwd中获得root用户信息

执行结果

BEGIN表示在gawk之前的动作,一般可以设置一些变量,打印开始的信息。ENDgawk处理完之后的动作。

如果在命令行下可以用

gawk –F: ‘$1==”root” {print}’ /etc/passwd

其中-F表示指定输入记录的字段分隔符为”

再查找一个名为cars的文件中所有代码honda字段的行

gawk /honda/ cars


sed编辑器

sed [-n] program [file-list]

sed [-n] –f program-file [file-list]

sed从指定文件或者标准输入中获取输入,将结果输出到标准输出。

sed程序写法:

[address[ ,address] ] instruction [argument-list]

sed –n ‘3,6 p’ testfile #testfile3~6行打印

sed默认是显示所有的行,-n选项可以指定只显示选定的行,如果上述命令没有-n,那么testfile3~6行将被打印两次。

sed也可以通过-f选项指定sed脚本

sed –f test.sh test.c #test.sh脚本处理test.c

sed –e:后面紧跟命令执行的脚本

sed –n –e ’3,6 p’ testfile #打印testfile3~6

sed–i:将输出送入原来的输入文件,如果带有suffixsed以原文件名加上后缀suffix备份原来的文件。

sed –i.bak –e ‘2,5 i\#abc’ testfile #jtestfile2~5行前面加#abc,输出到testfile,将原来的testfile的存储为testfile.bak

  • sed常用正则表达式

!:选中没有匹配的行,sed‘/./ !d’表示删除所有空行

^:匹配行开头,^A表示以A开头的行

[^]:表示取反,如[A-Za-z]表示匹配字母表中的任一字母,[^A-Za-z]表示匹配任一非字母表中的字母。。


$:表示匹配行尾A$表示以A结尾的行。

\<:匹配单词的左边界

\>:匹配单词的右边界,如\表示查找单词abc.

\(...\):标记匹配字符,如\(love\)被匹配,标记为1

sed ‘s/\(love\)\(.*\)/\1 you \2/’ test #love后面加上you


&:表示正则表达式匹配到的值

*:匹配零个或多个先前字符,如a*,表示匹配任意个aa.*表示a开头的所有文件(.*匹配任意多个非换行符字符)。

. :句号“.”匹配一个任意非换行符字符

sed ‘s/^./\t&/’ file #表达式(^.)匹配行首第一个字符不为空格的行,该命令对file中不以空格开头的行后移一个TAB字符。


sed –i.$$ ‘s/^[a-z]*[^a-z]$/\t&/g’ file#file中以字母开头并且不以字母结尾的行前面加一个TAB字符,写入输入文件,并将原输入文件以进程号为后缀重新保存。


sed=file | sed ‘N;s/\n/\t/’ #file加上行号

sed 's/.$//' #去掉非unix换行符的结尾

sed's/[ \t]*$//' #将每一行拖尾的“空白字符”(空格,制表符)删除

sed's/^[ \t]*//;s/[ \t]*$//' #将每一行中的前导和拖尾的空白字符删除

sed'$!N; /^\(.*\)\n\1$/!P; D' #只保留重复行中的第一行,其他行删除

分析一下:sed ‘$!N;/^\(.*\)\n\1$/!P;D’

N表示下一条指令输出当前的行,然后从输入中读入下一行,并且用下一条指令处理新读入的行。什么意思呢?

  1. 首先在sed中有pattern区和hold区的区别,pattern区表示当前处理的区域,而hold相当于一个备用的缓冲区,N可以读入下一行到当前的pattern区,也就是所N选项可以对当下两行进行处理。注意的是对于文件最后一行,N的操作会不成功,因为没有下一行了。$!选择了除最后一行外的所有行。综上:$!N的意思就是读取两行到pattern区等待同一行的下一条命令进行处理。

  2. ;表示命令分割,所以N的下一条指令为’/^\(.*\)\n\1$/!P;’,这条命令中^表示行首匹配,\(.*\)将第一行中所有内容标记为1,匹配\n后进入第二行的内容,\1为前面匹配的第一行的内容,$匹配行尾。!取反匹配结果,即如果匹配成功选择的是第二行,匹配失败,选择第一行。大写的P表示打印一行内容,小写p打印整个pattern区两行内容,所以PD都是对第二行的操作。

  • grep表达式

grep的正则表达式和sed的用法基本一样。增加如下:

x\{m\}:重复字符xm次,如:'0\{5\}'匹配包含5o的行。

grep '[a-z]\{5\}' aa #显示所有包含每个字符串至少有5个连续小写字符的字符串的行。

find ./ -name “*.c”|xargs grep –i ‘\’ #在当前的文件夹c文件中查找字符串var


sedgrep的正则表达式要作为重点来介绍

参考

http://sed.sourceforge.net/sed1line_zh-CN.html

http://man.chinaunix.net/newsoft/grep/open.htm








你可能感兴趣的:(Shell编程与vim控制命令)