Shell 笔记总结

Shell 笔记总结

  • 种类

    • Bourne Shell (/usr/bin/sh 或 /bin/sh)
    • Bourne Again Shell (/bin/bash)
    • C Shell (/usr/bin/csh)
    • K Shell (/usr/bin/ksh)
    • Shell for Root (/sbin/sh)
  • Shell 脚本

#!/bin/bash

echo 111

Shell 变量

变量名和等号之间不能有空格

for file in `ls /etc`; do
# 或 for file in $(ls /etc); do
	echo "${file}.log"
done

your_name="qinjx"
echo $your_name
echo ${your_name} # 推荐


# 只读变量
myURL="http://www.google.com"
readonly myURL
myURL="http://www.baidu.com" # /bin/sh: NAME: This variable is read only.

# 删除变量
unset ${your_name}
echo ${your_name}

# 变量作用域
## 局部变量
## 环境变量
## Shell 变量


# 字符串
## 单引号(原样输出)
str='this is a string'

## 双引号(可以有变量,可以出现转义字符)
your_name='runoob'
str="Hello, I know you are \"$your_name\"! \n"
echo -e $str

## 字符串操作

### 获取字符串长度
string="abcd"
echo ${#string} # 4
expr length "$string"

### 提取子字符串
string="runoob is a great site"
echo ${string:1:4} # unoo

### 查找子字符串
string="runoob is a great site"
echo `expr index "string" io` # 4  查找字符 i 或 o 的位置(哪个字线先出现就计算哪个)

# 数组
## 数组元素用空格符号分割开
## 形式 数组名=(值1 值2 ... 值n)

array_name=(value0 value1 value2 value3)

array_name=(
value0
value1
value2
value3
)

array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
array_name[n]=valuen # 可惜不使用连续的下标,且下标的范围没有限制

## 读取数组
## ${数组名[下标]}

value=${array_name[n]}
echo ${array_name[@]} # 获取数组中的所有元素

## 获取数组的长度
length=${#array_name[@]}
length=${#array_name[*]}

lengthn=${#array_name[n]} # 单个元素的长度

# 注释
## 行注释
# 这是一个注释
#### 用户配置区 开始 ####
#### 用户配置区 结束 ####

## 多行注释(EOF 可以使用其它符号)
:<<EOF
注释内容 ...
注释内容 ...
注释内容 ...
EOF

:<<'
注释内容 ...
注释内容 ...
注释内容 ...
'

:<<!
注释内容 ...
注释内容 ...
注释内容 ...
!


#
##
%
%%

  • # ## 表示从左边开始删除
    • # 表示从左边删除到第一个指定的字符
    • ## 表示从左边删除到最后一个指定的字符
  • % %% 表示从右边开始删除
    • % 表示从右边删除到第一个指定的字符
    • %% 表示从左边删除到最后一个指定的字符
var="http://www.aaa.com/123.htm"

echo ${var#*//} # www.aaa.com/123.htm
echo ${var##*/} # 123.htm
echo ${var%/*}  # http://www.aaa.com
echo ${var%%/*} # http

echo ${var:0:5} # http
echo ${var:7}   # www.aaa.com/123.htm
echo ${var:0-7:3} # 123
echo ${var:0-7}   # 123.htm
# 左边的第一个字符是用 0 表示,右边的第一字符用 0-1 表示


expr 5+6 # 5+6
expr 5 + 6 # 11
expr 5 * 6 # 输出错误
expr 5 \* 6 # 30




read -p "input a val: " a
read -p "input b val: " b
r=$[a+b]
echo "result = ${r}"



传递参数

# $0 执行的文件名

# $1 第一个参数
# $2 第二个参数
# $n 第 n 个参数

# $# 参数个数
# $* 以一个单字符串显示所有向脚本传递的参数
# $@ 在引号中返回每个参数

# $$ 脚本运行的当前进程 ID 号
# $! 后台运行的最后一个进程的 ID 号

# $- 显示 Shell 使用的当前选项(与 set 命令功能相同)
# $? 显示最后命令的退出状态(0 表示没有错误,其它值表示有错误)
# test.sh
echo '--- $* 演示 ---'
for i in "$*"; do
	echo $i
done

echo '--- $@ 演示 ---'
for i in "$@"; do
	echo $i
done

$ chmod +x ./test.sh
$ ./test.sh 1 2 3
--- $* 演示 ---
1 2 3
--- $@ 演示 ---
1
2
3
if [ -n "$1" ]; then
	echo '包含第一个参数'
else
	echo '没有包含第一个参数'
fi

[ $var -eq 0 ] 变量是否为 0
[ -e $var ] 文件是否存在
[ -d $var ] 是否目录
[[ $var1 = $var2 ]] 两个字符串是否相同

[] 常常可以使用 test 命令来代替

数组

E="Hello"
F="Old Man"
array_name=(A B "C" D $E $F) # ("A" "B" "C" "D" "Hello" "Old" "Man")
array_name[7]="Very Good"  # ("A" "B" "C" "D" "Hello" "Old" "Man" "Very Good")

i=2
echo $array_name[0]
echo $array_name[$i]




# 遍历
#!/bin/bash
arr=(1 2 3 4 5 6 7 8 9 10)
for a in ${arr[*]}
do
	echo $a
done


#!/bin/bash
my_arry=(a b "c","d" abc)
echo "-------FOR循环遍历输出数组--------"
for i in ${my_arry[@]};
do
  echo $i
done

echo "-------::::WHILE循环输出 使用 let i++ 自增:::::---------"
j=0
while [ $j -lt ${#my_arry[@]} ]
do
  echo ${my_arry[$j]}
  let j++
done

echo "--------:::WHILE循环输出 使用 let  "n++ "自增: 多了双引号,其实不用也可以:::---------"
n=0
while [ $n -lt ${#my_arry[@]} ]
do
  echo ${my_arry[$n]}
  let "n++"
done

echo "---------::::WHILE循环输出 使用 let m+=1 自增,这种写法其他编程中也常用::::----------"
m=0
while [ $m -lt ${#my_arry[@]} ]
do
  echo ${my_arry[$m]}
  let m+=1
done

echo "-------::WHILE循环输出 使用 a=$[$a+1] 自增,个人觉得这种写法比较麻烦::::----------"
a=0
while [ $a -lt ${#my_arry[@]} ]
do
 echo ${my_arry[$a]}
 a=$[$a+1]
done


# Bourne shell(原生kernel下)下不支持数组,只能通过模拟来实现类似数组功能
#!/bin/sh
#注意不是/bin/bash
echo "##############使用eval函数###############"
echo "使用参考:"
echo "http://www.runoob.com/linux/linux-comm-eval.html"
eval a1=bili
eval a2=nico
eval a3=yama

for i in 1 2 3 ; do
  eval echo "\$a$i"
done

#!/bin/sh
#注意不是/bin/bash
echo "##########################################"
echo "指令参考:"
echo "http://www.runoob.com/linux/linux-comm-expr.html"
:<<!
根据用户输入的一句话来定义数组
并遍历数组元素
!
echo "输入字符串(以空格分开):"
read str
i=0
for word in $str; do
    i=`expr $i + 1`
    eval a$i="$word"
    eval echo "数组的第 $i 个元素为: \$a$i"
done

基本运算符

# 算术运算符
	# 原生 bash 不支持简章的数学运算,但可以通过其它命令来实现(如 awk, expr)
val=`expr 2 + 2` # 表达式和运算符之间要有空格(2+2 是不对的)
echo $val
# + - * % / = == !=
`expr $a + $b`
`expr $a - $b`
`expr $a \* $b` # 需要转义 *, $(($a * b)) 不需要转义 *
`expr $a / $b`
`expr $a % $b`
val=$(expr 10 +20) # 推荐用 $() 代替 ``
val=$[ `expr 10 + 30` ]
val=$[ 10 + 20]

a=$b
[ $a == $b ] # 写成 [$a==$b] 是错的
[ $a != $b ]

if [ $a == $b ]
then
 	echo "a is equal to b"
else 
	echo "a is not equal to b"
fi

# 关系运算符(只支持数字,不支持字符串,除非字符串的值是数字)
[ $a -eq $b ]
[ $a -ne $b ]
[ $a -gt $b ]
[ $a -lt $b ]
[ $a -ge $b ]
[ $a -le $b ]


# 布尔运算符
[ !false ]
[ $a -lt 20 -o $b -gt 100 ]
[ $a -lt 20 -a $b -gt 100 ]

# 逻辑运算符
[[ $a -lt 100 && $b -gt 100 ]]
[[ $a -lt 100 || $b -gt 100 ]]

# 字符串运算符
[ $a = $b ]
[ $a != $b ]
[ -z $a ] # 检查字符串是否为 0
[ -n "$a"] # 检查字符串是否不为 0
[ $a ] # 检查字符串是否不为空

# 文件测试运算符
[ -b $file ] # 是否为块设备文件
[ -c $file ] # 是否为字符设备文件
[ -d $file ] # 是否为目录
[ -f $file ] # 是否为普通文件(不是目录、设备文件)
[ -g $file ] # 是否设置了 SGID 位
[ -k $file ] # 是否设置了粘着位(Sticky Bit)
[ -p $file ] # 是否为有名管道
[ -u $file ] # 是否设置了 SUID 位
[ -r $file ] # 文件是否可读
[ -w $file ] # 文件是否可写
[ -x $file ] # 文件是否可执行
[ -s $file ] # 文件是否不为空(文件大小是否大于 0)
[ -e $file ] # 文件或目录是否存在
[ -S $file ] # 文件是否为 socket
[ -L $file ] # 文件是否存在并且是一个符号链接

# [[]] 只是 [] 的扩充,能够支持 >, < 符号运算不需要转义,支持逻辑运算符 ||, &&,不再使用 -a, -o
# [[]]: >, <, &&, ||
# []: \>, \<, -a, -o
# 数值比较
# [ expression1 OP expression2 ]: -gt, -lt, -ge, -le, -eq, -ne
# ((expression1 OP expression2)): >, <, >=, <=, ==, !=
# >, <, ==, != 也可以进行字符串比较
# == 和 != 进行字符串比较时,可用 [ string1 OP string2 ] 或 [[ string1 OP string2 ]]
# > 和 < 进行字符串比较时,需要用 [ string1 \OP string2 ] 或 [[ string1 OP string2 ]]

echo 命令

echo It is a test
echo 'It is a test'
echo "It is a test"
echo "\"It is a test\""

echo -e "OK! \n" # -e 开启转义
echo -e "OK! \c" # \c 不换行
echo "It is a test"
# OK! It is a test

echo 'It is a test' > myfile
echo '$name\"' # $name\"

echo `date` # Wed Jan 29 14:28:47 2020

read 命令

read -p '请输入一段文字:' -n 6 -t 5 -s password
echo -e "\npassword is ${password}"

# -p 输入提示文字
# -n 输入字符长度限制(-n 6 达到 6 位自动结束)
# -t 输入限时
# -s 隐藏输入内容

重定向

> 重定向输出到某个位置,替换原有文件的所有内容
>> 重定向追加到某个位置,在原有文件的末尾添加内容
< 重定向输入某个位置文件

2> 重定向错误输出
2>> 重定向错误追加输出到文件末尾
&> 混合输出错误的和正确的都输出

printf 命令

# 语法:
# printf format-string [arguments ...]

# 不会像 echo 自动添加换行符
# 使用引用文本或空格分隔的参数,外面可以在 printf 中使用格式化字符串,还可以制定字符串的宽度、左右对齐方式等

printf "Hello, Shell\n"


printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg  
printf "%-10s %-8s %-4.2f\n" 郭靖 男 66.1234 
printf "%-10s %-8s %-4.2f\n" 杨过 男 48.6543 
printf "%-10s %-8s %-4.2f\n" 郭芙 女 47.9876 
姓名     性别   体重kg
郭靖     男      66.12
杨过     男      48.65
郭芙     女      47.99

# %-10s 指一个宽度为10个字符(-表示左对齐,没有则表示右对齐),任何字符都会被显示在10个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来
# %-4.2f 指格式化为小数,其中.2指保留2位小数


# format-string为双引号
printf "%d %s\n" 1 "abc"

# 单引号与双引号效果一样 
printf '%d %s\n' 1 "abc" 

# 没有引号也可以输出
printf %s abcdef

# 格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
printf %s abc def

printf "%s\n" abc def

printf "%s %s %s\n" a b c d e f g h i j

# 如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
printf "%s and %d \n"

# 输出结果
1 abc
1 abc
abcdefabcdefabc
def
a b c
d e f
g h i
j  
 and 0


# \a 警告字符,通常为ASCII的BEL字符
# \b 后退
# \c 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
# \f 换页(formfeed)
# \n 换行
# \r 回车
# \t 水平制符
# \v 垂直制表符
# \\ 一个字面上的反斜杠字符
# \ddd 表示 1 到 3 位数八进制值的字符,仅在格式字符串中有效
# \0ddd 表示 1 到 3 位的八进制值字符

$ printf "a string, no processing:<%s>\n" "A\nB"
a string, no processing:<A\nB>

$ printf "a string, no processing:<%b>\n" "A\nB"
a string, no processing:<A
B>

$ printf "www.runoob.com \a"
www.runoob.com $                  #不换行


:<<!
%d %s %c %f 格式替代符详解:

d: Decimal 十进制整数 -- 对应位置参数必须是十进制整数,否则报错!

s: String 字符串 -- 对应位置参数必须是字符串或者字符型,否则报错!

c: Char 字符 -- 对应位置参数必须是字符串或者字符型,否则报错!

f: Float 浮点 -- 对应位置参数必须是数字型,否则报错!

如:其中最后一个参数是 "def",%c 自动截取字符串的第一个字符作为结果输出。
!

$  printf "%d %s %c\n" 1 "abc" "def"
1 abc d

%b: 字符串--相对应的参数被视为含有要被处理的转义序列之字符串
$ printf "a string, no processing:<%b>\n" "A\nB"
a string, no processing:<A
B>
# 无论时在格式字符串内还是在使用 %b 所打印的参数字符串里,大部分的转义序列都是被相同对待。
# 无论如何,\c 与 \0ddd 只有搭配 %b 使用才有效,而 \ddd 只有在格式字符串里才会被解释

%f 格式化浮点数默认支持 6 位小数:
$ printf "%d %s %c %f\n" 10 "abc" "def" "3.1415926"
10 abc d 3.141593          # 格式化浮点数默认支持小数点后六位,后面多出的四舍五入

test 命令

# 用于检查某个条件是否成立(可以进行数值、字符和文件三个方面的测试)

# 数值测试
# -eq
# -ne
# -gt
# -ge
# -lt
# -le

num1=100
num2=100
if test $[num1] -eq $[num2]
then
	echo '两个数相等!'
else
	echo '两个数不相等!'
fi

a=5
b=6
result=$[a+b] # 注意等号两边不能有空格

# 字符串测试
# =
# !=
# -z 字符串    字符串长度是否为 0
# -n 字符串    字符串长度是否不为 0

str1="ru1noob"
str2="runnob"
if test $str1 = $str2
then
	echo '两个字符串相等'
else
	echo '两个字符串不相等'
fi

# 文件测试
# -e $file 文件存在则为真
# -r $file 文件存在且可读则为真
# -w $file 文件存在且可写则为真
# -x $file 文件存在且可执行则为真
# -s $file 文件存在且至少有一个字符则为真
# -d $file 文件存在且为目录则为真
# -f $file 文件存在且为普通文件则为真
# -c $file 文件存在且为字符型特殊文件则为真
# -b $file 文件存在且为块特殊文件则为真
# -O $file 判断对象是否存在且属于当前用户
# -G $file 判断对象是否存在且属于当前用户组
# [ "/data/file1" -nt "/data/file2" ] 判断 file1 是否比 file2 新
# [ "/data/file1" -ot "/data/file2" ] 判断 file1 是否比 file2 旧

if test -e /bin/bash
then
	echo '文件已存在!'
else
	echo '文件不存在!'
fi

# 逻辑操作符
# ! -a -o,优先级依次降低

if test -e ./notFile -o -e /bin/bash
then
	echo '至少有一个文件存在'
else
	echo '两个文件都不存在'
fi


result=$[a + b]
result=`expr $a + $b`



if [ ! -d "/data/" ];then
  mkdir /data
  else
  echo "文件夹已经存在"
fi
if [ ! -f "/data/filename" ];then
  echo "文件不存在"
  else
  rm -f /data/filename
fi
if [ -d "/data/" ];then
  echo "文件夹存在"
  else
  echo "文件夹不存在"
fi
if [ -f "/data/filename" ];then
  echo "文件存在"
  else
  echo "文件不存在"
fi

流程控制

条件分支
# 流程控制执行语句不可为空

if condition
then
	command1
	command2
	...
	commandN
fi

# 写成一行(适用于终端命令)
if [ $(ps -ef | grep -c "ssh") -gt 1 ] ; then echo "true";fi


if condition
then
	command1
	command2
	...
	commandN
else
	command
fi



if condition
	command1
then
elif condition2
then
	command2
else
	commandN
fi


a=10
b=20
if [ $a == $b ]
then
	echo 'a 等于 b'
elif [ $a -gt $b ]
then
	echo 'a 大于 b'
elif [ $a -lt $b ]
then
	echo 'a 小于 b'
else
	echo '没有符合的条件'
fi


num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
    echo '两个数字相等!'
else
    echo '两个数字不相等!'
fi
循环控制
for var in item1 item2 ... itemN
do
	command1
	command2
	...
	commandN
done

# 写成一行
for var in item1 item2 ... itemN; do command1; command2 ... commandN; done;

# for循环即执行一次所有命令,使用变量名获取列表中的当前取值
# in列表是可选的,如果不用它,for循环使用命令行的位置参数

for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done

for str in 'This is a string'
do
    echo $str
done


while condition
do
    command
done

int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done


echo '按下 <CTRL-D> 退出'
echo -n '输入你最喜欢的网站名: '
while read FILM
do
    echo "是的!$FILM 是一个好网站"
done

# while循环可用于读取键盘信息
# while循环用于不断执行一系列命令,也用于从输入文件中读取数据;命令通常为测试条件

# 无限循环
while :
do
    command
done

while true
do
    command
done

for (( ; ; ))

# 一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用
# condition 一般为条件表达式,如果返回值为 false,则继续执行循环体内的语句,否则跳出循环
until condition
do
    command
done

a=0

until [ ! $a -lt 10 ]
do
   echo $a
   a=`expr $a + 1`
done


# 取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac


echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
    1)  echo '你选择了 1'
    ;;
    2)  echo '你选择了 2'
    ;;
    3)  echo '你选择了 3'
    ;;
    4)  echo '你选择了 4'
    ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
    ;;
esac


# 跳出循环
# break命令允许跳出所有循环(终止执行后面的所有循环)。
while :
do
    echo -n "输入 1 到 5 之间的数字:"
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你输入的数字为 $aNum!"
        ;;
        *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
            break
        ;;
    esac
done

# continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。
while :
do
    echo -n "输入 1 到 5 之间的数字: "
    read aNum
    case $aNum in
        1|2|3|4|5) echo "你输入的数字为 $aNum!"
        ;;
        *) echo "你输入的数字不是 1 到 5 之间的!"
            continue
            echo "游戏结束"
        ;;
    esac
done



case 值 in
模式1)
    command1
    command2
    command3
    ;;
模式2)
    command1
    command2
    command3
    ;;
*)
    command1
    command2
    command3
    ;;
esac

site="runoob"

case "$site" in
   "runoob") echo "菜鸟教程"
   ;;
   "google") echo "Google 搜索"
   ;;
   "taobao") echo "淘宝网"
   ;;
esac

for((assignment;condition:next));do
    command_1;
    command_2;
    commond_..;
done;
for((i=1;i<=5;i++));do
    echo "这是第 $i 次调用";
done;
# 与 C 中相似,赋值和下一步执行可以放到代码之前循环语句之中执行,这里要注意一点:如果要在循环体中进行 for 中的 next 操作,记得变量要加 $,不然程序会变成死循环
函数
[ function ] funname [()]
{
    action;
    [return int;]
}
# 以带function fun() 定义,也可以直接fun() 定义,不带任何参数
# 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255

#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

demoFun(){
    echo "这是我的第一个 shell 函数!"
}
echo "-----函数开始执行-----"
demoFun
echo "-----函数执行完毕-----"




funWithReturn(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    read aNum
    echo "输入第二个数字: "
    read anotherNum
    echo "两个数字分别为 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"
# 函数返回值在调用该函数后通过 $? 来获得。
# $? 仅对其上一条指令负责,一旦函数返回后其返回值没有立即保存入参数,那么其返回值将不再能通过 $? 获得


function demoFun1(){
    echo "这是我的第一个 shell 函数!"
    return `expr 1 + 1`
}

demoFun1
echo $? # 2
echo $? # 0

# 注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可

# 函数参数
# 在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值
funWithParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73
# 注意,$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数

# 函数与命令的执行结果可以作为条件语句使用。要注意的是,和 C 语言不同,shell 语言中 0 代表 true,0 以外的值代表 false

#!/bin/bash

echo "Hello World !" | grep -e Hello
echo $?
echo "Hello World !" | grep -e Bye
echo $?
if echo "Hello World !" | grep -e Hello
then
    echo true
else
    echo false
fi

if echo "Hello World !" | grep -e Bye
then
    echo true
else
    echo false
fi

function demoFun1(){
    return 0
}

function demoFun2(){
    return 12
}

if demoFun1
then
    echo true
else
    echo false
fi

if demoFun2
then
    echo ture
else
    echo false
fi
其执行结果如下:

Hello World !
0
1
Hello World !
true
false
true
false

# grep 是从给定字符串中寻找匹配内容的命令。首先看出如果找到了匹配的内容,会打印匹配部分且得到的返回值 $? 为 0,如果找不到,则返回值 $? 为 1。
# 接下来分别将这两次执行的 grep 命令当作条件语句交给 if 判断,得出返回值 $? 为 0,即执行成功时,条件语句为 true,当返回值 $? 为 1,即执行失败时,条件语句为 false。

# 之后再用函数的 return 值作为测试,其中 demoFun1 返回值为 0,demoFun2 返回值选择了任意一个和 0 不同的整数,这里为 12。

# 将函数作为条件语句交给 if 判断,得出返回值为 0 时,依然为 true,而返回值只要不是 0,条件语句都判断为 false。

输入/输出重定向

command > file	将输出重定向到 file
command < file	将输入重定向到 file
command >> file	将输出以追加的方式重定向到 file
n > file 将文件描述符为 n 的文件重定向到 file
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file
n >& m 将输出文件 m 和 n 合并
n <& m 将输入文件 m 和 n 合并
<< tag	将开始标记 tag 和结束标记 tag 之间的内容作为输入

# 需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。

$ who > users
$ cat users
_mbsetupuser console  Oct 31 17:35 
tianqixin    console  Oct 31 17:35 
tianqixin    ttys000  Dec  1 11:33 

$ echo "菜鸟教程:www.runoob.com" > users
$ cat users
菜鸟教程:www.runoob.com
$ echo "菜鸟教程:www.runoob.com" >> users
$ cat users
菜鸟教程:www.runoob.com
菜鸟教程:www.runoob.com

$ wc -l users
2 users

$  wc -l < users
2 

command1 < infile > outfile
# 同时替换输入和输出,执行command1,从文件infile读取内容,然后将输出写入到outfile中

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件:
标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。

默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file

$ command 2 > file # 如果希望 stderr 重定向到 file,可以这样写
$ command 2 >> file

$ command > file 2>&1 # 如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写
$ command >> file 2>&1

command < file1 >file2 # command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2


# Here Document
# Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序
# 它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command
command << delimiter
    document
delimiter
# 结尾的delimiter 一定要顶格写,前面不能有任何字符,后面也不能有任何字符,包括空格和 tab 缩进。
# 开始的delimiter前后的空格会被忽略掉。

$ wc -l << EOF
    欢迎来到
    菜鸟教程
    www.runoob.com
EOF
3          # 输出结果为 3 行

#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

cat << EOF
欢迎来到
菜鸟教程
www.runoob.com
EOF

欢迎来到
菜鸟教程
www.runoob.com

# 如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null
command > /dev/null
# /dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果


command > /dev/null 2>&1 # 如果希望屏蔽 stdout 和 stderr,可以这样写
# 放在>后面的&,表示重定向的目标不是一个文件,而是一个文件描述符

换言之 2>1 代表将stderr重定向到当前路径下文件名为1的regular file中,而2>&1代表将stderr重定向到文件描述符为1的文件(即/dev/stdout)中,这个文件就是stdout在file system中的映射

而&>file是一种特殊的用法,也可以写成>&file,二者的意思完全相同
此处&>或者>&视作整体,分开没有单独的含义



# 顺序问题
find /etc -name .bashrc > list 2>&1
# 我想问为什么不能调下顺序,比如这样
find /etc -name .bashrc 2>&1 > list

xxx > list 2>&1

先将要输出到stdout的内容重定向到文件,此时文件list就是这个程序的stdout,再将stderr重定向到stdout,也就是文件list

xxx 2>&1 > list

先将要输出到stderr的内容重定向到stdout,此时会产生一个stdout的拷贝,作为程序的stderr,而程序原本要输出到stdout的内容,依然是对接在stdout原身上的,因此第二步重定向stdout,对stdout的拷贝不产生任何影响

$ find /etc -names "*.txt"  >list 2>&1
从左往右执行,执行到 >list,此时的 stdout 为 list;而执行到 2>&1,表示 stderr 重定向到 stdout,这里也就是 list 文件。

因为 [ find /etc -names "*.txt" ] 这条命令是错误的( -names 应该是 -name)。

本来要输出到终端屏幕的错误信息:

find: unknown predicate `-names`
被重定向到了 stdout 也就是 list 文件中,所以屏幕不会出现错误信息,而是打印到了 list 文件中。
cat list 可以查看到 find: unknown predicate `-names' 就在里面。


直接在 FreeBSD 或者 csh 中使用 command > file 2>&1 时候会得到这个错误:Ambiguous output redirect。

出错的原因在于 FreeBSD 默认使用 csh,在 csh 中如果想把标准输出和错误输出同时重定向到一个文件,需要用下面命令 command >& file

文件包含

# 和其他语言一样,Shell 也可以包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件

# 语法
. filename   # 注意点号(.)和文件名中间有一空格
或
source filename

# test1.sh
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

url="http://www.runoob.com"

# test2.sh
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

#使用 . 号来引用test1.sh 文件
. ./test1.sh

# 或者使用以下包含文件代码
# source ./test1.sh

echo "菜鸟教程官网地址:$url"

$ chmod +x test2.sh 
$ ./test2.sh 
菜鸟教程官网地址:http://www.runoob.com

# 注:被包含的文件 test1.sh 不需要可执行权限。

参考

  • https://www.runoob.com/linux/linux-shell.html

记录

  • 2020/01/29 18:08 创建
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈挨踢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值