Linux 笔记--脚本

脚本的参数

参数变量

$* 传递给脚本/函数的所有参数(把所有参数当成一个字符串)
[email protected] 参数名字
$0 文件名字(first.sh…)
$# 总共有多少个参数
$$ 脚本的 PID
$! 上一个被执行的命令的 PID(后台运行的进程)
IFS=, # 将函数参数的分隔符改成用‘,‘ 例如 IFS=:

var=test
echo ${#var}
4
echo $#var
0var
echo $# == 0
# 2014-10-16 16:21:41

## 测试 $* 和 $# 的区别
function countargs {
    echo $# args;
}
countargs "$*"
countargs "[email protected]"
## 将上面的代码保存为一个文件, sh FILENAME a b c
## 3 args
## 1 args

使用默认参数

${varname:-word} 如果 varname 为 null,返回 word, (${count:-0})
${varname:+word} 如果 varname 为 null,返回 null,否则返回 word,测试一个变量的存在性.${count:+1}返回 1,即‘true‘
${varname:=word} 如果 varname 为 null,将其设置为 word, 不能设置位置参数和特殊参数
${varname:?message} 如果 varname 为 null,打印 varname:后跟信息 message,并退出当前命令或脚本,捕获为定义变量导致的错误
${varname:NUM 返回从 NUM 开始的字符串, 开头以 0 计算
${varname:NUM:LENG 返回从 NUM 开始的 LENG 长度字符串

count=frogfotman
${count:4}    返回 footman
${count:4:4}  返回 foot

sort -nr $1 | head -${2:-10}   # the first version
# 当后面没有接文件的时候, 会有一些奇怪的信息

filename=${1:?"filename missing"}
howmany=${2:-10}
sort -nr $filename | head -$howmany   # the second version
# 当后面没有接文件的时候, 输出的错误信息有点不尽人意

filename=$1
filename=${filename:?"filename missing."}
howmany=${2:-10}
sort -nr $filename | head -$howmany    # the third version

filename=$1
filename=${filename:?"filename missing."}
howmany=${2:=1}
sort -nr $filename | head -$howmany    # the fourth version
# 会把 1 赋值给 $2, shell 会提示出错, "cannot assign in this way"

filename=$1
filename=${filename:?"filename missing"}
howmany=$2
sort -nr $filename | head -${howmany:=10}   # the fifth version

filename=$1
filename=${filename:?"filename missing"}
howmany=$3
header=$2
echo -e -n ${header:+"ablums artist\n"}
# 如果变量为空什么都不输出, 连空行也不输出, 如果不为空就输出
# echo $head   # 的值不是后面的字符串...注意区分,他只是返回
sort -nr $filename | head -${howmany:=3}

getopts

while getopts ":ab:c" opt; do
    case $opt in
        a) echo ‘this is a‘ ;;
        b) echo ‘this is b‘
            echo "args b is $OPTARG" ;;
        c) echo ‘this is c‘ ;;
        \?) echo ‘usage: alice [-a][-b bargs] [-c] args...‘
            exit 1;;
    esac
done
echo $OPTIND
shift $(($OPTIND - 1))

# 输入: ./my.sh -a -a -b
# 输出:
# this is a
# this is b
# 4

# 输入: ./my.sh -a -b 5 -c
# 输出:
# this is a
# this is b
# args b is 5
# this is c
# 5

# 输入: ./my.sh  -acb 4
# this is a
# this is c
# this is b
# args b is 4
# 3

数组

name[0]=abc;
name[1]=def;
name[2]=ghi;
##   ==
name=(abc def ghi)
##   ==
name=([0]=abc [1]=def [2]=ghi)

for i in "${name[@]}"; do
    echo $i
done

文件描述符

<> FILE: 文件作为输入和输出
2> FILE: 将错误写入文件  或者 2>>FILE
&> FILE: 定向标准输出和标准错误到 FILE  或者 &>>FILE
2>&1: 把 2 输出到 1
2<&0: 把 2 出入到 0

模式匹配

${VALUE#pattern} 匹配以 pattern 开头的部分,只匹配一次
${VALUE##pattern} 匹配以 pattern 开头的部分,匹配至多次
${VALUE%pattern} 匹配以 pattern 结尾的部分,只匹配一次
${VALUE%%pattern} 匹配以 pattern 结尾的部分,匹配至多次
${VALUE/OLDSTRING/NEWSTRING} 替换字符串,只替换一个匹配到
${VALUE//OLDSTRING/NEWSTRING} 替换字符串,替换全部匹配到
# 从前面开始往后面删除匹配到的, 留下最后没被匹配的
% 从后面往前面开始删除, 留下前面的

temp=/home/sunx/Work/bin
echo ${temp#*/}      # home/sunx/Work/bin
echo ${temp%%/*}     # 

echo ${temp##*/}     # bin
echo ${temp%/*}      # /home/sunx/Work/bin

temp=test.c
file1=${temp#*\.}
echo ${file1}        # c

file2=${temp%*\.*}   # test

temp=test.c.cpp
file=${temp#*\.}     # c.cpp
file=${temp##*\.}    # cpp
file=${temp%\.*}     # test.c
file=${temp%%\.*}    #

脚本控制流

test

文件属性

-e 该名字是否存在
-f 该名字是否存在且为档案 file
-d 改名字是否存在且为目录 dirctory
-b 该名字是否存在且为 block device 装置
-c 该名字是否存在且为 charcter device
-S 该名字是否存在且为 socket 档案
-p 该名字是否存在且为 FIFO(pipe) 档案
-L 该当名是否存在且为一个 link 档案

文件权限

-r 是否可读
-w 是否可写
-x 是否可执行

2 个文件比较

-nt (newer than)file1 是否比 file2 新
-ot (older than)file1 是否比 file2 旧
-ef 是否相等, 判断 hard link 经常使用

2 个数值比较

-eq 是否相等
-ne not equal
-gt (greater than)大于
-lt (less than) 小于
-ge (greater than or equal) 大于等于
-le (less than or equal) 小于等于

字符串

test -z string 判定字符串是否为 0? 若 string 为空字符串, 则是 true
test -n string 判定字符串是否非 0?
test str1 = str2 判定 str1 是否等于 str2
test str1 != str2 判定是否不等,一定要加空格

判断相等的时候 等于号左右留空格, 否则被当成赋值.

test 中使用逻辑判断

-a test -r file -a -x file
-o test -r file -o -x file
test ! -x file, 当 file 不具有 x 权限时, 才是 true

[] 判断

[] 等价于 test

[ "$HOME" == "$MAIL" ]
# 在 bash 里面用 = 和用 == 是一样的
# [ ] 前后都要加空格

read -p "Please input (Y/N): " yn
[ "$yn" == "Y" -o "$yn" == "y" ] && echo "OK, continue" && exit 0
[ "$yn" == "N" -o "$yn" == "n" ] && echo "Oh, interrupt!" && exit 0
echo "I don‘t know what your choice is" && exit 0

[ "$yn" == "Y" -o "$yn" == "y" ]
# 等价于
[ "$yn" == "Y" ] || [ "$yn" == "y"]

if 语句

if [ 条件判断式 ]; then
    ...
fi

read -p "please input(Y/N):" yn
if [ "$yn" == "Y" ]||[ "$yn" == "y" ]; then
    echo "ok, yes continue"
    exit 0
fi

if [ 条件判断式 ]; then
    ...
else
    ...
fi

if [ 条件判断式 ]; then
    ...
elif [ 条件判断式二 ]; then
    ...
else
    ...
fi

for

for animal in dog cat elephant; do
    echo "there are ${animal}s..."
done
# dogs
# cats
# elephants

users=$(cut -d ‘:‘ -f1 /etc/passwd)
# users=`cut -d ‘:‘ -f1 /etc/passwd`
for usename in $users; do
    id $username
    finger $username
done
# $((...))      对数学表达式求值
   # echo $((2*10))    20
   # echo $((2**3))    8

# echo $((s))   # 结果是 0, 说明这样的操作 shell 会自动给他 0,接下来看下面
for((i=0; i<=10; ++i)) do
    s=$(($s+$i))   # s = s + i
done

while

while [ "$yn" != "yes" -a "$yn" != "YES" ]; do
    read -p "please input yes/YES to stop this program: " yn
done
echo "ok! you input the correct answer."

until

until [ "$yn" == "yes" -o "$yn" == "YES" ]; do
    read -p "please input yes/YES to stop this program: " yn
done
echo "ok! you input the correct answer."
# 直到条件满足才退出循环.

case

case $1 in
    "hello")
        echo "hello, how are you?"
        ;;
    "")
        echo "you must input parameters, example: {$0 someword}"
        ;;
    *)   # 相当于 C 语言的 default
        echo "usae $0 {hello}"
        ;;
# 也可以在 case 里面用 | 來表示或, 例如
case $1 in
        123 | 456)
            ...
esac  # end

select

select name in LIST; do
    ...
done

temp=$(ls *.c)  # a.c b.c
select file in $temp; do
    if [ $file == "a.c" ]; then
        echo "a.c"; fi
    if [ $file == "b.c" ]; then
        echo "b.c"; fi
done
1) a.c
2) b.c
#? 1
a.c
#? 2
b.c
#? 3
bash: [: ==: unary operator expected
bash: [: ==: unary operator expected
#? 1
a.c
#?

脚本函数

如果从别的文件中调用函数, 例文件名字是 a.sh

. /PATH_TO/a.sh
或者是
source ./PATH_TO/a.sh

function FUNCTNAME() {
}
FUNCTNAMENAME() {
}
## 这 2 种形式都是可以声明和定义一个函数的
unset -f FUNCTNAME
function afunc {
    echo in function : $0 $1 $2
    var1="in function"
    echo var1: $var1
}
var1="outside function"
echo var1: $var1
echo $0: $1 $2
afunc funcarg1 funcarg2
echo var1: $var1
echo $0: $1 $2

# var1: outside function
# ./Function.sh: arg1 arg2
# in function : ./Function.sh funcarg1 funcarg2  # 从这里开始调用函数
# var1: in function
# var1: in function    # var1 还是 in function
# ./Function.sh: arg1 arg2
function afunc {
    # local var1
    echo in function : $0 $1 $2
    # var1="in function"     # 如果这句话被注释掉, 下面以行的 var1 的值就变成了空, 但是如果同时把 local 的声明也注释掉就是 outside...
    echo var1: $var1
}                            # 由上面的注释可以知道, 再脚本里面定义的变量可以在函数里面使用, 但是如果函数定义了该变量就不行了
var1="outside function"
echo var1: $var1
echo $0: $1 $2
afunc funcarg1 funcarg2
echo var1: $var1
echo $0: $1 $2

# var1: outside function
# ./Function.sh: arg1 arg2
# in function : ./Function.sh funcarg1 funcarg2
# var1: in function
# var1: outside function  # var1 的值还是函数的, 函数外的 var1 的值没有影响
# ./Function.sh: arg1 arg2
function printit() {
    echo -n "Your choice is $1"
}
echo "This program will print your selection !"
case $1 in
    "one")
        printit; echo $1 | tr ‘a-z‘ ‘A-Z‘ # 将参数做大小写转换!
        ;;
    "two")
        printit; echo $1 | tr ‘a-z‘ ‘A-Z‘
        ;;
    "three")
        printit; echo $1 | tr ‘a-z‘ ‘A-Z‘
        ;;
    *)
        echo "Usage $0 {one|two|three}"
        ;;
esac
##############上面是程序的的参数, ..区别于函数的的参数. .........###############

## 程序的参数是在 shell 命令中跟在脚本名字后面的, 函数的参数是在脚本里面调用函数时候, 跟在脚本后面的

################下面是函数的参数, ..区别于程序的参数. .........#################
function printit() {
    echo -n "Your choice is $1  "

echo "This program will print your selection !"
case $1 in
    "one")
        printit 1; echo $1 | tr ‘a-z‘ ‘A-Z‘ # 将参数做大小写转换!
        ;;
    "two")
        printit 2; echo $1 | tr ‘a-z‘ ‘A-Z‘
        ;;
    "three")
        printit 3; echo $1 | tr ‘a-z‘ ‘A-Z‘
        ;;
    *)
        echo "Usage $0 {one|two|three}"
        ;;
esac
}
printit one

# result
# Your choice is one  This program will print your selection !
# Your choice is 1  This program will print your selection !  # 注意 printit 1 也会继续调用函数
# Usage a.sh {one|two|three}
# ONE

脚本调试

sh [-nvx] FILE
-n 不执行,仅检查语法问题
-v 执行前,先输出脚本
-x 将使用到的脚本输出

cat a.sh
echo "hello" || echo "123"

sh -n a.sh   # 检查语法问题, 没输出,说明没问题,似乎没用 :D

sh -v a.sh
echo "hello" || echo "123"
hello

sh -x a.sh
+ echo hello
hello
时间: 2024-12-26 22:56:06

Linux 笔记--脚本的相关文章

Linux Shell脚本编程学习笔记和实战

http://www.1987.name/141.html shell基础 终端打印.算术运算.常用变量 Linux下搜索指定目录下特定字符串并高亮显示匹配关键词 从键盘或文件中获取标准输入 [read命令] 文件的描述符和重定向 数组.关联数组和别名使用 函数的定义.执行.传参和递归函数 条件测试操作与流程控制语句 获取时间日期格式和延时 [date.sleep命令] 内部字段分隔符IFS和脚本的调试DEBUG 显示.读取或拼接文件内容 [cat命令] 文件查找与打印文件列表 [find命令]

LINUX SHELL脚本攻略笔记[速查]

Linux Shell脚本攻略笔记[速查] 资源 shell script run shell script echo printf 环境变量和变量 pgrep shell数学运算 命令状态 文件描述符和重定向 cat 数组和关联数组 alias date 调试脚本 函数和参数 管道 读取命令输出 read 字段分隔符和迭代器 循环 比较和测试 find xargs tr md5sum sha1sum 对目录进行校验 sort uniq tempfile split bash变量匹配切分 exp

Linux Shell脚本与Vim常用操作笔记

本篇笔记记录最最基本的vim和shell操作. ShellScript能干什么 Shellscript类似与Windows的批处理,可以把很多指令汇总到一起,于是可以很容易地通过一个操作执行多个命令.很轻量,有效率. 在Vim中编写 Vim/Vi编辑器很强大,功能非常多,快捷键.指令更多,只需要知道最常用的就够了. Vi有3种工作模式 1.命令模式 进去之后的默认模式就是命令模式.能接受命令,但是不明文显示. 2.输入模式 命令模式按下a键就进入输入模式(还能按i.o.s等等).按Esc返回命令

《Linux Shell脚本攻略》 笔记 第一章:Shell起步基础

<Linux Shell脚本攻略> 笔记 第一章:Shell起步基础 1.变量:在bash中,每一个变量的值都是字符串.无论你给变量赋值时,有没有使用引号,值都会以字符串的形式存储. 2.var=value; //赋值操作 var = value: //相等操作 3.获取字符串的长度 [[email protected] ~]$ var=yang [[email protected] ~]$ length=${#var} [[email protected] ~]$ echo $length

《Linux Shell脚本攻略》 笔记 第二章:常用命令

<Linux Shell脚本攻略> 笔记 第二章:常用命令 1.cat cat -s //多个空白行压缩成一个 cat *.txt | tr -s '\n'   //移除空白行 cat -n //加行号 2.find 沿着文件层次结构向下遍历,匹配符合条件的文件,并执行相应的操作. eg: find ./ ! -name "*.txt" -print [[email protected] program_test]# find ./  -type f -name "

《Linux Shell脚本攻略》 笔记 第三章:文件操作

<Linux Shell脚本攻略> 笔记 第三章:文件操作 1.生产任意大小的文件 [[email protected] dd_test]# [[email protected] dd_test]# dd if=/dev/zero of=junk.data bs=1k count=10 10+0 records in 10+0 records out 10240 bytes (10 kB) copied, 0.00137023 s, 7.5 MB/s 2.文件系统相关测试 [ -f $file

《Linux Shell脚本攻略》 笔记 第四章:高效文本处理

<Linux Shell脚本攻略> 笔记 第四章:高效文本处理 1.IP地址的正则表达式: [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3} 2.grep用法 //在多级目录中对文本进行递归检索 [[email protected] program_test]# grep "yang" ./ -Rn ./test.txt:6:laoyang ./right.txt:1:1 yang man //忽略大小写匹配 [[email pr

《Linux Shell脚本攻略》 笔记 第六章:打包压缩

<Linux Shell脚本攻略> 笔记 第六章:打包压缩 //1.打包.解包 [[email protected] program_test]# tar -cf output.tar 11.txt 22.txt 33.txt [[email protected] program_test]# tar -xf output.tar -C ./tar-file/  //-C指定要提取到哪个路径? //列举出归档文件中的内容 [[email protected] program_test]# ta

LInux Shell 脚本笔记

*************************** list.txt : 目录 ******************************** 1. variable.sh2. condition.sh3. control.sh4. AndOr.sh5. statementBlock.sh6. function.sh7. command_1.sh8. old_version_set.sh9. new_version_set.sh10. command_2.sh11. command_3.s