Skip to content

shell笔记 #90

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 comparison result
str1 = str2 string equal
str1 != str2 string not equal
-n str string is not null
-z str string is null(an empty string)
num1 -eq num2 exprs are equal
eq, ne, gt, ge, lt, le ...
! expr1 is false?
-d file is directory?
-e file exist?
-f file is file?
-r file is readable?
-w file is writable?
-x file is executable?
-g file if set-group-id is set on file?
-u file if 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

for i in foo bar 43
do
  echo $i
done

或

for i in $(ls f*.sh); do
  lpr $file
done

while

echo "Enter password"
read trythis
while [ "$trythis" != "secret" ]; do
  echo "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/sh
echo "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
    ;;
esac

exit 0

AND

打印出hello in else

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

OR

打印出hello in if

rm -f file_one
if [ -f file_one ] || echo "hello" || echo "there"
then
  echo "in if"
else
  echo "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" gregl@190.100.2.2 < /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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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