linux shell要点与技巧
来源:互联网 发布:淘宝爆款打造小技巧 编辑:程序博客网 时间:2024/06/05 22:32
1. shell 中命令或者表达式返回0表示true,非0表示false。
2. 几个常用的环境变量:$HOME -- 用户目录 $PATH -- 默认可执行路径 $PWD -- 当前目录 $HOSTNAME -- 主机名 $RANDOM -- 返回一个0到32767之间的随机整数 $BASH_VERSION -- bash版本号
3. Bash中有三种类型的变量:string,integer,array。
创建数组:
创建数组的方法就是圆括号:array=(a b c),还可以指定下标:array=( [0]=a [1]=b [10]=c [20]=d)得到一个稀疏数组。获取一个文件名数组(永远不要在脚本中使用ls命令来获取文件名,请使用通配符!):
$ files=$(ls) # BAD, BAD, BAD!$ files=($(ls)) # STILL BAD!
$ files=(*) # Good! No word splitting problem.+=() 语法可以将一个或多个值加入已有的数组中。如 files+=( "file1" "$file" "${names[@]}" )。
数组的用法:
${array[i]}可以引用数组变量array下标为i的元素,如果下标为i的元素不存在则返回空。${array[@]}可以获取数组中所有元素,通常用于遍历数组。${array[*]}得到数组的字符串表示,即所有元素用分隔符(默认空格,可通过设置IFS变量的值改变)相连组成的字符串。${#array[@]}获得数组长度,即数组中元素数。
for name in "${names[@]}"; do echo "$name"; done #记得加双引号!!
$ ( IFS=,; echo "Today's contestants are: ${names[*]}" ) #不能用${names[@]},IFS=,;必须有分号Today's contestants are: Bob,Peter,lhunath,Big Bad John
printf语句可以很优雅的打印数组中的所有元素,至于为什么它会有循环的功能,I don't know either.
$ printf "%s\n" "${names[@]}"
数组还有个很好的性质:index=1; echo "${array[index]}"; 可以直接使用变量index(当然$index也是ok的)获取下标为1的元素,而且可以在[]中进行算术运算,echo "${array[index + 2]}"; 。
关联数组Associative Array(你可以使用字符串进行索引,有点像unordered map):
$ declare -A fullNames$ fullNames=( ["lhunath"]="Maarten Billemont" ["greycat"]="Greg Wooledge" )
$ for user in "${!fullNames[@]}" #顺序是不定的,${!array[@]}得到所有key,${array[@]}得到所有value> do echo "User: $user, full name: ${fullNames[$user]}."; done
4. [[ ]]关键字。[[ ]]关键字可以用于测试,比[ ] 和test方便很多,完全可以取代它们。在[[ ]]中可以直接使用 && || 组合逻辑表达式,直接使用各种比较运算符进行字符串的比较(包括=进行通配符匹配,=~进行正则表达式匹配,数字比较请使用(( ))),而且不必担心其中变量展开的word splitting问题(指值含有空格的变量在使用时若不加双引号会造成错误,比如foo="ab cd", [ $foo = "ab cd" ] 会出现命令错误)。需要注意的一点是,[[ ]]中出现在右侧的变量不加双引号时允许通配符扩展,加双引号时则不允许。但总之,如果你不确定,请给你的变量引用加上双引号,你出错的概率会最小。例:
$ foo=[a-z]* name=lhunath$ [[ $name = $foo ]] && echo "Name $name matches pattern $foo"Name lhunath matches pattern [a-z]*$ [[ $name = "$foo" ]] || echo "Name $name is not equal to the string $foo"Name lhunath is not equal to the string [a-z]*
5. 如果要把含有空格的变量作为某个命令的参数,一定要把这个变量用双引号括起来(word splitting问题)。比如a='2013-04-07 16:25' ,命令 date +%s -d $a 会报错date: extra operand `16:25',因为$a展开后被命令当成2个参数了。正确的方法是:date +%s -d “$a”。
6. 命令组合。你可以通过 && 或者 || 把不同的命令组合起来作为 if then... else ... fi 的简写,比如 cmd1 && cmd2 || cmd3 。最正宗的命令组合是{ cmd; cmd; } 的形式,注意花括号两边有空格而且最后一个分号不能少。当然,使用逻辑符号和花括号这两种形式可以结合使用。输入重定向也可用于命令组合,如:
{ read firstLine read secondLine while read otherLine; do something done} < file
7. 通配符与正则表达式并不是一回事,前者用来匹配文件名,后者用来匹配模式。基本的通配符包括 * ? [...] 三种,分别表示匹配任意多字符、0或1个字符、括号内的某个字符;扩展的通配符可以将若干通配符组合,包括 *(list) ?(list) +(list) @(list) !(list) 5种,分别表示任意多、0或1个、至少1个、1个、非,list表示若干通配符的组合,用 & 或 | 相连,比如:
$ lsnames.txt tokyo.jpg california.bmp$ echo !(*jpg|*bmp)names.txtbash中经常要用 shopt -s extglob 命令开启扩展通配符后才能使用。通配符也可以用来进行变量值的比较:
$ filename="somefile.jpg"$ if [[ $filename = *.jpg ]]; then> echo "$filename is a jpeg"> fisomefile.jpg is a jpeg
这是通配符唯一不是匹配文件名的用法。通配符是直接使用的,不要加(双)引号。
8. 正则表达式不要加引号,这在bash3.2之后是强制要求。所以,可以直接使用正则表达式,或者将模式串保存在变量中,再使用变量,如:
$ langRegex='(..)_(..)'$ if [[ $LANG =~ $langRegex ]]> then> echo "Your country code (ISO 3166-1-alpha-2) is ${BASH_REMATCH[2]}."> echo "Your language code (ISO 639-1) is ${BASH_REMATCH[1]}."> else> echo "Your locale was not recognised"> fi
9. 花括号扩展。花括号扩展只有两种形式,{a,b}c 扩展至 ac bc,{1..4} 0 扩展至 10 20 30 40。花括号扩展在通配符扩展之前,用来生成单词,不能用来匹配。
$ echo th{e,a}nthen than$ echo {/home/*,/root}/.*profile/home/axxo/.bash_profile /home/lhunath/.profile /root/.bash_profile /root/.profile$ echo {1..9}1 2 3 4 5 6 7 8 9$ echo {0,1}{0..9}00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19
10. 管道命令都是在单独的子shell中执行的,其中的变量不会传递给外部。因此,试图通过管道命令计算全局变量是行不通的。把若干个命令用圆括号括起来也表示在子shell中执行:( cmd; cmd; )。解决这类问题的方法有进程替换(process substitution),其形式为<(cmds;) 或 >(cmds;),前者通常用其输出作为其它命令的输入,后者则是用其它命令的输出作为它的输入。
# Working example, using bash syntax.i=0while read line; do ((i++)) ...done < <(sort list1)echo "$i lines processed"
11. 交互式shell中正确输入 '\t' 的方法是:按Ctrl+v,然后再按Tab。但是脚本中Ctrl+v再按Tab则会自动转化成空格,这时要使用$'\t',sort -t$'\t' -k3,3 file才可以。Ctrl+d输入EOF标志可用于结束输入。
12. 如果你想要判断if [[ $var = foo || $var == bar || $var = more ]] 而又不想写很多次$var,可以使用case语句:
# bash case "$var" in foo|bar|more) ... ;; esac
case中的每个匹配项可以使用通配符而不是正则表达式。
13. 如何处理命令行参数。POSIX标准要求参数选项和参数值之间必须有空格,即-f filename,bash和dash允许没有空格-ffilename。
14. 子进程是无法修改父进程环境的,包括父进程中的变量、当前工作目录、打开的文件描述符、资源限制等等。因此,调用一个脚本改变PWD是不会成功的,这个脚本会在子shell中执行,对当前shell没有任何影响。让脚本在当前shell中执行有两种方式:source命令或者“.”。
echo 'cd /tmp' > "$HOME/mycd" # Create a file that contains the 'cd /tmp' command.. $HOME/mycd # Source that file, executing the 'cd /tmp' command in the current shell.pwd # Now, we're in /tmp
{ some commands} >msg.log 2>&1 #或者使用简写 &>msg.log,将stdout和stderr都重定向到msg.log
# Keep both stdout and stderr unmolested. exec 3>&1 4>&2 foo=$( { time bar 1>&3 2>&4; } 2>&1 ) # Captures time only. exec 3>&- 4>&-
16. HereDoc和HereString。可以用来将一段文字或者一个变量的值重定向到stdin。
cat <<'XYZ' #这段HereDoc的名字为XYZ,因为名字被单引号括起来了,所以其内容都作为普通字符,变量不会扩展。My home directory is $HOMEXYZ#输出:My home directory is $HOME。如果名字不用单引号括起来,$HOME会扩展。
$ grep proud <<<"$USER sits proudly on his throne in $HOSTNAME." #HereStringlhunath sits proudly on his throne in Lyndir.
HereDoc和HereString可在同一行跟其它重定向连用。$ cat <<EOF > file> My home dir is $HOME> EOF
17. 将stderr重定向到管道。
exec 3>&1 # Save current "value" of stdout.myprog 2>&1 >&3 | grep ... # Send stdout to FD 3.exec 3>&- # Now close it for the remainder of the script.
18. 删除变量、函数或者别名。unset 的 -f -v 参数可缺省,缺省时函数优先。
$ unset -f myfunction
$ unset -v 'myArray[2]' # unset element 2 of myArray. The quoting is important to prevent globbing.
$ unalias rm
19. 作业控制。
Ctrl-Z sends SIGTSTP to the foreground job (usually suspending it)暂停
Ctrl-C sends SIGINT to the foreground job (usually terminating it)终止
Ctrl-\ sends SIGQUIT to the foreground job (usually causing it to dump core and abort)
jobs [options] [jobspec ...]: 列出所有后台作业和暂停的作业. Options 包括 -p (list process IDs only), -s (list only suspended jobs), and -r (list only running background jobs).
参数jobspec 可以是:
%n to refer to job number n.
%str to refer to a job which was started by a command beginning with str. 没有则出错。
%?str to refer to a job which was started by a command containing str. 没有则出错。
%% or %+ to refer to the current job: the one most recently started in the background, or suspended from the foreground. fg and bg will operate on this job if no jobspec is given.
%- for the previous job (the job that was %% before the current one).
kill can take a jobspec instead of a process ID.
disown tells bash to forget about an existing job. This keeps bash from automatically sending SIGHUP to the processes in that job, but also means it can no longer be referred to by jobspec.
fg [jobspec]: bring a background job to the foreground.
bg [jobspec ...]: run a suspended job in the background.
suspend: suspend the shell (mostly useful when the parent process is a shell with job control).
$ echo $$ $! #$$得到当前进程id,$!得到上个命令对应进程的id
根据命令名字获取进程ID。在脚本中请使用$!保存你关注的子进程id,不要使用下面命令去获取pgrep name #获取包含name的命令的pidps aux | grep -v grep | grep nameps aux | grep [n]ame #the easiest way
kill -0 $pid #测试$pid的进程是否存在,若存在则返回true
# Read all the files (from a text file, 1 per line) into an array.IFS=$'\n' read -r -d '' -a files < inputlist
#!/bin/bashset -mtrap 'kill %%' EXIT #设置脚本终止时的自陷程序,%%指当前作业号即最后一个后台执行的管道命令command1 | command2 &wait #等待子进程结束,还可以指定pid。如 wait $pid; exitcode=$? 等待特定的子进程结束并获取其退出码。
A child process inherits many things from its parent:
- Open file descriptors. The child gets copies of these, referring to the same files.
Environment variables. The child gets its own copies of these, and changes made by the child do not affect the parent's copy.
Current working directory. If the child changes its working directory, the parent will never know about it.
- User ID, group ID and supplementary groups. A child process is spawned with the same privileges as its parent. Unless the child process is running with superuser UID (UID 0), it cannot change these privileges.
System resource limits. The child inherits the limits of its parent. A process that runs as superuser UID can raise its resource limits (setrlimit(2)). A process running as non-superuser can only lower its resource limits; it can't raise them.
umask.
sed -i 's/old/new/g' ./* # GNU,最方便的方法,-i参数表示在副本中修改并替换原文件,相当于直接修改原文件
ex -sc '%s/old/new/g|x' file
在vim中,如果没有old字符串,程序会卡住,需要使用e参数来忽略错误。ex -sc '%s/old/new/ge|x' filevim中,还可以使用argdo参数来减少ex进程的数量。
# Bash 4+ ex -sc 'argdo %s/old/new/ge|x' file* #处理以file开头的文件
# Bash. 使用扩展的通配符shopt -s extglob[[ $foo = *[0-9]* && $foo = ?([+-])*([0-9])?(.*([0-9])) ]] && echo "float number"
# Bash. Put the RE in a var for backward compatibility with versions <3.2regexp='^[-+]?[0-9]*(\.[0-9]*)?$' #使用正则表达式if [[ $foo = *[0-9]* && $foo =~ $regexp ]]; then echo "'$foo' looks rather like a number"else echo "'$foo' doesn't look particularly numeric to me"fi
# Bash shopt -s extglob var="${var##*( |$'\t'|$'\n')}" # trim the left var="${var%%*( |$'\t'|$'\n')}" # trim the right或者使用read和HereString,以空字符串(相当于NUL)做分隔符。会忽略前后空白,将中间的部分赋值给x。
# Bash read -rd '' x <<< "$x"
- linux shell要点与技巧
- Linux Shell学习要点
- Storyboard要点与技巧
- Linux Shell常用技巧
- linux SHELL技巧
- linux SHELL常用技巧
- linux SHELL技巧
- Linux Shell常用技巧
- Linux Shell常用技巧
- Linux Shell常用技巧
- Linux Shell常用技巧
- Linux shell 常用技巧
- Linux Shell高级技巧
- Linux shell 技巧
- Linux Shell常用技巧
- Linux Shell常用技巧
- Linux Shell常用技巧
- Linux Shell高级技巧
- 块级与内联元素的使用注意
- 孙鑫VC++深入详解:Lesson6 Part2 -- MFC菜单更新机制 用该机制实现 Enable or Disable MenuItem
- android学习笔记(一)环境搭建
- C# ASP.NET中无刷新页面 弹出对话框,并且页面跳转
- 使用JDK中的安全包对数据进行加解密
- linux shell要点与技巧
- 分享一篇关于seo的文章
- 展望未来,从现在做起
- 复选框与文字水平对齐方法
- 对Java程序设计的感想
- 少了外链不知搜索引擎优化还可否继续
- 我和菜鸟一起学android4.0.3源码之硬件gps简单移植
- 01背包和完全背包 的完整讲解版 包含 一维数组实现 和二维数组实现题目
- UVA 253 - Cube painting