Linux系统编程20-shell脚本入门

发布时间 2023-06-27 09:48:54作者: 言叶以上

shell 是一个作为用户与Linux系统间接口的程序, 默认的shell程序 /bin/sh实际上是对程序 /bin/bash的一个连接

管道与重定向

重定向

重定向输出:
ls -l / > lsoutput.txt

使用>>附加输出内容:
ps >> lsoutput.txt

标准错误:
test.c 2> err.log

回收站丢弃输出信息:
kill -1 1234 >/dev/null 2>&1

重定向输入:
more < lsoutput.txt

管道

使用重定向对 ps 命令输出排序:

  • ps aux > psout.txt
  • sort psout.txt > pssort.out

使用管道对 ps 命令输出排序:

  • ps aux | sort > pssort.out
  • ps aux | sort | more
  • ps -xo comm | sort | uniq | grep -v sh | more 查看系统运行所有进程名

shell程序语言

通配符:

  • *: 字符串
  • ?: 单个字符
  • [set]: 方括号中任何一个单字符
  • {}: 任意字符串放到一个集合中

变量

  • 所有变量都被看作字符串来存储, 使用echo $x打印
  • 使用read命令将输入赋值给一个变量
  • 环境变量:
    • $HOME 家目录
    • $PATH 搜索命令
    • $PS1 命令提示符
    • $PS2 二级提示符
    • $IFS 输入域分隔符
    • $0 脚本名
    • $# 传递给脚本参数个数
    • $1,$2,.. 脚本程序参数
    • $* 一个变量中列出所有参数
    • $@ $*的变体, 不收IFS影响, 更好的选择
    • $$ 脚本进程号
#!/bin/sh

salutation="Hello"
echo $salutation
echo "The program $0 is now running"
echo "The second parameter was $2"
echo "The first parameter was $1"
echo "The parameter list was $*"
echo "The user's home directory is $HOME"

echo "Please enter a new greeting"
read salutation

echo $salutation
echo "The script is now complete"

exit 0
$ ./3_try_var foo bar baz
Hello
The program ./3_try_var is now running
The second parameter was bar
The first parameter was foo
The parameter list was foo bar baz
The user's home directory is /home/codespace
Please enter a new greeting
world!
world!
The script is now complete

条件循环

test -f <filename>: 是一个普通文件为真

[ -d <filename> ]: 是一个目录为真(有空格0)

#!/bin/sh

if [ -f /bin/bash ] 
then
    echo "file /bin/bash exists"
fi

if [ -d /bin/bash ]
then
    echo "/bin/bash is a directory"
else
    echo "/bin/bash is NOT a directory"
fi

使用if语句

#!/bin/sh

echo "Is it morning? please answer yes or no?"
read timeofday

if [ $timeofday = "yes" ]; then
    echo "Good morning"
elif [ $timeofday = "no" ]; then
    echo "Good afternoon"
else
    echo "sorry, $timeofday not recognized. Enter yes or no"
    exit 1
fi

exit 0
Is it morning? please answer yes or no?
yes
Good morning

for语句

#!/bin/sh

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

while语句

#!/bin/sh

echo "Enter password"
read trythis

while [ "$trythis" != "secret" ]; do
    echo "Sorry, try again"
    read trythis
done
exit 0

until 语句

#!/bin/sh

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

#now ring the bell and announce the expected user.

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

exit 0

case语句

#!/bin/sh

echo "Is it morning? please answer yes  or no"
read timeofday

case "$timeofday" in 
    yes) echo "Good Morning";;
    no ) echo "Good Afternoon";;
    y  ) echo "Good Morning";;
    n  ) echo "Good Afternoon";;
    *  ) echo "Sorry, answer not recognized";;
esac

exit 0
#!/bin/sh

echo "Is it morning? please answer yes  or no"
read timeofday

case "$timeofday" in 
    yes | y | Yes | YES )   echo "Good Morning";;
    n* | N* )               echo "Good Afternoon";;
    * )                     echo "Sorry, answer not recognized";;
esac

exit 0
#!/bin/sh

echo "Is it morning? please answer yes  or no"
read timeofday

case "$timeofday" in
    [yY] | [Yy][Ee][Ss] )
        echo "Good morning"
        echo "up bright and early this morning"
        ;;
    [Nn]*)
        echo "Good afternoon"
        ;;
    * )
        echo "Sorry, answer not recognized"
        echo "please answer yes or no"
        exit 1
        ;;
esac

exit 0

命令列表

AND: 只有在前面所有的命令都执行成功的情况才执行下一条命令

#!/bin/sh

touch file_one
rm -f file_two

if [ -f file_one ] && echo "Hello" && [ -f file_two ] && echo " there"
then
    echo "in if"
else
    echo "in else"
fi

exit 0

OR: 执行一系列命令直到有一条命令成功为止, 后面的命令不再执行

函数

#/bin/sh

foo(){
    echo "Function foo is executing"
}

echo "script starting"
foo
echo "script ended"

exit 0

命令

break命令

#!/bin/sh

rm -rf fred*
echo > fred1
echo > fred2
mkdir fred3
echo >fred4

for file in fred*
do
    if [ -d "$file" ]; then
        break;
    fi
done

echo first direcory starting fred was $file

rm -rf fred*

exit 0

:命令

#!/bin/sh

rm -f fred
if [ -f fred ]; then
    :
else
    echo file fred did not exist
fi

exit 0

continue命令: continue 语句的数字参数指定要跳过的循环级别。如果提供的数字参数大于嵌套层数,则会跳过最外层的循环

for x in 1 2 3
do
    echo before $x
    continue 1
    echo after $x
done

eval 命令

foo=10
x=foo
eval y='$'$x
echo $y

exec命令:用wall替换shell

exec wall "Thanks for all the fish"

expr命令:将参数当做一个表达式求值

x=`expr $x + 1`
x=$(expr $x + 1)

set, unset命令: 为shell设置参数变量

#!/bin/sh

echo the date is $(date)
set $(date)
echo The month is $2

exit 0

trap命令: 捕捉信号

#!/bin/sh

trap 'rm -f /tmp/my_tmp_file_$$' INT # 接收中断信号SIGINT
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$ # 当前日期时间写入my_tmp_file_$$

echo "press interrupt (CTRL-C) to interrupt...."
while [ -f /tmp/my_tmp_file_$$ ];  #检查临时文件是否存在
do
    echo File exists
    sleep 1
done
echo The file no longer exists

trap INT #恢复对中断信号(SIGINT)的默认处理方式
echo creating file /tmp/my_tmp_file_$$
date > /tmp/my_tmp_file_$$

echo "press interrupt (control-C) to interrupt...."
while [ -f /tmp/my_tmp_file_$$ ];
do
    echo File exists
    sleep 1
done

echo we never get here 
exit 0

命令的执行

语法: $(command) 或 `command`

echo The current directory is $PWD
echo The current user are $(who)

算术扩展: 使用$((...))完成简单的算术运算

#!/bin/sh

x=0
while [ "$x" -ne 10 ]; 
do
    echo $x
    x=$(($x+1))
done

exit 0

参数扩展

#!/bin/sh

unset foo #删除变量 foo,如果存在的话
echo ${foo:-bar} #输出为 "bar"

foo=fud
echo ${foo:-bar} #输出为 "fud"

foo=/usr/bin/X11/startx
echo ${foo#*/} #删除匹配的最短字符串,这里是 "*/",即删除第一个斜杠及其之前的内容
echo ${foo##*/} #删除的是最长匹配的字符串

bar=/usr/local/etc/local/networks
echo ${bar%local*} #末尾删除匹配的最短字符串
echo ${bar%%local*} #末尾删除的是最长匹配的字符串

exit 0

运行

bar
fud
usr/bin/X11/startx
startx
/usr/local/etc/
/usr/

here文档:允许我们在脚本中直接输出多行文本,无需使用 echo 命令或多个字符串

#!/bin/sh

cat <<!FUNCY! # 指定了 Here 文档的结束标记
hello
this is a here
document
!FUNCY! # 结束标记

dialog工具

创建一个简单的消息框:
dialog --msgbox "Hello World" 9 18

创建标题"check me"复选框:
dialog --title "Check me" --checklist "Pick Numbers" 15 25 3 1 "one" "off" 2 "two" "on" 3 "three" "off"

  • 标题:Check me
  • 类型:checklist
  • 提示信息:Pick Numbers
  • 高15行 宽25行 3个选项
  • 编号:1 文本:one 状态: off

一个复杂的dialog工具

#!/bin/sh

# ask some questions and collect the answer

dialog --title "Questionnaire" --msgbox "Welcome to my simple survey" 9 18

dialog --title "Comfirm" --yesno "Are you willing to take part?" 9 18

if [ $? != 0 ];
then
    dialog --infobox "Thank you anyway" 5 20
    sleep 2
    dialog --clear
    exit 0
fi

dialog --title "Questionnaire" --inputbox "Please enter your name" 9 30 2>_1.txt
Q_NAME=$(cat _1.txt)

dialog --menu "$Q_NAME, what music do you like best?" 15 30 4 1 "Classical" 2 "Jazz" 3 "Country" 4 "Other" 2>_1.txt
Q_MUSIC=$(cat _1.txt)

if [ "$Q_MUSIC" = "1" ];
then    
    dialog --title "Likes Classical" --msgbox "Good choice!" 12 25
else
    dialog --title "Doesn't like Classical" --msgbox "Shame" 12 25
fi

sleep 2
dialog --clear
exit 0