Skip to content

shell笔记#90

@uniquejava

Description

@uniquejava

shell

变量与变量展开

hello=world echo $hello hello="i am world" echo $hello echo hello world echo -n "enter your name:" (-n去掉行尾的回车) read name echo $name 
  1. $是取变量的值,所以总是出现在=号的右边
  2. =号前后不能有任何空格
  3. =号后面的字符串如果不包含空格可以不加""
  4. echo后面字符串即使包含空格也可不加"", 如果要正常输出变量中的换行符,则必须加双引号
  5. shell视所有变量为字符串类型.
  6. 单引号不展开变量, 仅原样输出字符串, 双引号会展开变量.
  7. 强制展开变量的办法:嵌套使用单引号,或者整体使用双引号或者拼字符串
    $ sed -n '1 c$HOME' package.json(不会展开变量)
    $HOME
    $ sed -n "1 c$HOME" package.json(整体使用双引号)
    /home/cyper
    $ sed -n '1 c'$HOME'' package.json(嵌套使用单引号)
    /home/cyper
    $ sed -n '1 c'$HOME package.json(拼字符串)
    /home/cyper

输出重定向

3个特殊的文件描述符0 stdin, 1 stdout, 2 stderr.

格式:command FILE_DESCRIPTOR>outputFileName

foo 1>ok.txt 2>error.txt 

因为foo命令不存在,所以出错信息输出到了error.txt中,注意到同时生成了一个空的ok.txt文件, 其中标准输出重定向1>可以简写成>

怎么将正常的及错误的消息输出到同一文件foo 1>ok.txt 2>&1, 即使用&1来表示文件描述符为1对应的输出文件,在这里它们同时指向ok.txt.

引号

'原样输出 "会先做expansion 

参数

$HOME 打印出/home/cyper $0: shell script的名字 $#: 参数个数 $$: 运行脚本时的process ID $1,$2, ...传递给脚本的参数 $*: 所有参数使用$IFS分隔(默认为空格) $@: 同$*但总是使用空格分隔 $?: 命令的退出状态,0成功,非0失败 PS1,PS2: 命令提示符 

快速测试

 $ IFS=’‘ $ set foo bar bam $ echo$@“ foo bar bam $ echo$*“ foobarbam $ unset IFS $ echo$*“ foo bar bam

条件测试

if test -f fred then ... elif test -d fred; then ... else ... fi 

if [ -f fred.c ] then ... fi 

if [ -f fred.c ]; then ... fi 

[]和其中包含的测试条件必须用空格隔开

条件比较

string comparisonresult
str1 = str2string equal
str1 != str2string not equal
-n strstring is not null
-z strstring is null(an empty string)
num1 -eq num2exprs are equal
eq, ne, gt, ge, lt, le...
! expr1is false?
-d fileis directory?
-e fileexist?
-f fileis file?
-r fileis readable?
-w fileis writable?
-x fileis executable?
-g fileif set-group-id is set on file?
-u fileif set-user-id is set on file?

You may be wondering what the set-group-id and set-user-id (also known as set-gid and set-uid) bits are. The set-uid bit gives a program the permissions of its owner, rather than its user, while the set-gid bit gives a program the permissions of its group.The bits are set with chmod,using the s and g options.The set-gid and set-uid flags have no effect on files containing shell scripts, only on executable binary files.

特殊情况

if [ $timeofday = "yes" ]这段可能有问题, 当timeofday为空的时候if [ = "yes"]语法不合规,最好写成if [ "$timeofday" = "yes" ]

for

foriin foo bar 43 doecho$idone

foriin$(ls f*.sh);do lpr $filedone

while

echo"Enter password"read trythis while [ "$trythis"!="secret" ];doecho"sorry, try again"read trythis done

util

who查看当前系统有哪个登录用户, 比如who|grep cyper返回0, 而who|grep green返回1, 这里我们只关心script的执行情况(0 or 1), 不关心stdout.

# 如果参数1对应的用户没有出现, 就等待60s后再次检测until who | grep "$1"> /dev/null do sleep 60 done# 响铃echo -e '\a'echo"**** $1 has just logged in ****"exit 0

case

基本结构

case"$x"in pattern | pattern2 ) statements; * ) echo"default case"; esac

例子:

#!/bin/shecho"Enter your name?"read timeofday case"$timeofday"in yes | y | Yes | YES ) echo"Good morning"echo"It's cool" ; [nN]*) echo"Good afternoon" ; *) echo"sorry"exit 1 ; esacexit 0

AND

打印出hello in else

touch file_one rm -rf file_two if [ -f file_one ] &&echo"hello"&& [ -f file_two ] &&echo" there"thenecho"in if"elseecho"in else"fi

OR

打印出hello in if

rm -f file_one if [ -f file_one ] ||echo"hello"||echo"there"thenecho"in if"elseecho"in else"fi

Statement Blocks

可以用AND/OR选择性的执行语句块

get_confirm &&{echo "hello" echo "dome some other thing" } 

braces and brackets

braces()中的command在subshell中执行,在期间修改的env var不会影响current shell(比如执行了cd命令).在brackets{}中包含的command在当前shell中执行.

set -e

遇到错误即退出, 不继续执行后续脚本

set -o noclobber

打开此选项是为了防止使用重定向符>意外覆盖文件,如果要强制覆盖,使用>|.

Here document

用来快速提供多行输入,常用于交互式命令比如telnet, ftp.

command << terminaor [input ...] 或者 command <<- terminator [input ...] 

每次读一行,直到读到某行是terminator时结束,<<-会把input中每行前面的tabs去掉。
登录到一个远程机器并把某文件mail给本机。

$ telnet << END > open 190.100.2.1 > gregl password > mail -s "remote userlogs" [email protected] < /var/log/userlog > quit > END 

substitution

文件名替换: 使用w*,?,[a-z],
命令替换: $(command), $(< filename)

* 0或多个字符 ? 单个字符 [a-z0-9] 范围内单个字符 [!0-9] 范围外单个字符,和正则^不一样 $(command) 执行command并把输出结果作为其它命令的参数 $(< filename) 将filename的内容作为其它命令的参数 echo '*' 如果需要转递特殊字符做为参数,需要使用引号或\以防止该符号被shell解释. echo \* 同上 echo "*" 同上 

Date

DATE=`date +%Y-%m-%d`$(date +%F) DATE=`date +%Y-%m-%d:%H:%M:%S`

其中%Y-%m-%d <==> %F, 输出2017-04-26

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions