[关闭]
@wanghuijiao 2021-04-01T16:55:38.000000Z 字数 5953 阅读 609

[学习笔记1] Bash Tutorial语法学习

学习笔记


0. 前言

1. 变量

1.1 基础用法

  1. $ a="value"
  2. $ echo ${a}
  3. value
  4. # 常用操作,不能省{}的情况
  5. $ cp $a ${a}_backup
  6. # 内嵌在字符串中,双引号展开变量,对变量进行解释
  7. $ echo "${a} is cool"
  8. value is cool
  9. # 单引号原样输出
  10. $ echo '${a} is cool'
  11. ${a} is cool
  12. # "\"是使特殊字符保持原样,"\$"会使得"$"仅作为普通字符,"$a"不再被替换
  13. $ echo "\$a is cool"
  14. $a is cool
  15. $ echo '\$a is cool'
  16. \$a is cool

1.2 内置变量

  1. $ cat watch-arguments.sh
  2. #!/bin/bash
  3. echo "script file name : $0"
  4. echo "first argument : $1"
  5. echo "second argument : $2"
  6. $ ./watch-arguments.sh good job
  7. script file name : ./watch-arguments.sh
  8. first argument : good
  9. second argument : job

1.3 环境变量

  1. $ CUDA_VISIBLE_DEVICES='0,1' python train.py
  1. $ python -c 'import os; import sys;print os.environ.get(sys.argv[1])' some_var
  2. # 直接在shell中赋值的变量,子进程不可见
  3. None
  4. $ some_var=kk python -c 'import os; import sys;print os.environ.get(sys.argv[1])' some_var
  5. #直接在子进程运行前赋值的变量,是可见的.
  6. $ echo $some_var
  7. # 上一行中的单行赋值方式不会"污染"全局环境, 仅对后面接的命令有效.
  8. (输出为空)
  9. $ export some_var='kk'
  10. $ echo $some_var
  11. kk
  12. $ python -c 'import os; import sys;print os.environ.get(sys.argv[1])' some_var
  13. kk

1.4 进阶之source

  1. $ echo 'k1=v1' > vars.sh
  2. $ chmod +x ./vars.sh
  3. $ ./vars.sh
  4. $ echo $k1 # 什么都没有输出来。原因是刚才 'k1=v1' 在一个独立的sh脚本运行时,会在新开的子shell中运行,子shell运行结束后,其中的变量(k1)也不复存在。因此子shell中的这句赋值不会对父shell有任何影响。
  5. $ source ./vars.sh
  6. $ echo $k1 # 这一次赋值的效果出现在了父shell中。原因是 source 后的脚本,不再是新开子shell运行,source使得 vars.sh 中的每一行,像在父shell中执行一样。本例中,就是 k1=v1 在父shell中运行了。
  7. v1

1.5 输出赋值

  1. $ ret=$(cat readme.txt)
  2. $ echo $ret
  3. Working in 837 is a lot of fun.
  4. $ ret=`cat readme.txt`
  5. $ echo $ret
  6. Working in 837 is a lot of fun.

2. 运算

2.1 let

  1. $ let "a=5+6"
  2. $ echo $a
  3. 11
  4. $ x=5
  5. $ y=6
  6. $ let "z=x*y"
  7. $ echo $z
  8. 30

2.2 expr

  1. $ expr 5 + 6
  2. 11
  3. $ foo=$(expr 5 + 6)
  4. $ echo $foo
  5. 11

2.3 双括号

  1. $ a=$((5+6))
  2. $ echo $a
  3. 11

3. 判断语句

3.1 语法

  1. if <condition>
  2. then
  3. <cmd>
  4. else
  5. <cmd>
  6. fi

else语句可以省略。比如:

  1. #!/bin/bash
  2. tmp=35
  3. # -ge great or equal
  4. if [ ${tmp} -ge 30]
  5. then
  6. echo "It's hot, we should turn on the AC."
  7. else
  8. fi
  1. # 其中-e用来判断文件是否存在。
  2. if [ -e /bin/ls ]
  3. then
  4. echo "Your 'ls' binary is on the usual path."
  5. else
  6. echo "I can't find the 'ls' binary."
  7. fi
  8. # 比较大小
  9. $ test 5 -ge 4
  10. $ echo $?
  11. 0
  12. # 其中$?是上一个命令的返回结果。Test命令的返回结果,0表示结果是True或者命令运行成功;1表示结果是False或者命令运行不成功

3.2 布尔运算

  1. code_review="pass"
  2. regression_test="pass"
  3. if [ $code_review = "pass" ] && [ $regression_test = "pass" ]
  4. then
  5. echo "ship it!"
  6. fi

4. 循环

4.1 for

  1. $ for var in <list>
  2. do
  3. <command>
  4. done
  5. # 示例
  6. $ cat test-loop.sh
  7. #!/bin/bash
  8. for x in 830 837 846 859
  9. do
  10. echo "Our teams are in room ${x}."
  11. done
  1. echo {1..3}
  2. for i in {1..3}
  3. do
  4. echo "I got ${i} tickets."
  5. done
  6. # 输出
  7. 1 2 3
  8. I got 1 tickets.
  9. I got 2 tickets.
  10. I got 3 tickets.
  1. for ((i=1; i<=3; i++))
  2. do
  3. echo "I fixed ${i} bugs."
  4. done
  5. # 输出
  6. I fixed 1 bugs.
  7. I fixed 2 bugs.
  8. I fixed 3 bugs.

4.2 util

  1. until [ <some test> ]
  2. do
  3. <commands>
  4. done
  1. suffix=1
  2. until [ ! -e "foo${suffix}" ]
  3. do
  4. let suffix++
  5. done
  6. echo "The file name foo${suffix} is good."

4.3 break

  1. # 发现第一个有鱼的餐厅,打印并退出
  2. for res in YUYU LanZhouLaMian ShaoFen fish
  3. do
  4. # -q 表示不显示,在${res}.txt文件中查找fish字符
  5. grep -q fish ${res}.txt
  6. # $?用来获取上一条命令的返回值
  7. found=$?
  8. if [ $found = 0 ]
  9. then
  10. echo "We have fish from $res!"
  11. break
  12. fi
  13. done

4.4 continue

  1. # 跳过所有含辣的餐馆
  2. for res in YUYU LanZhouLaMian ShaoFen fish
  3. do
  4. grep -q spicy ${res}.txt
  5. found=$?
  6. if [ $found = 0 ]
  7. then
  8. continue
  9. fi
  10. done

5. 函数

  1. function_name (){
  2. <commands>
  3. }
  4. # 或者
  5. function function_name{
  6. <commands>
  7. }

调用时,直接调用function_name即可。必须在调用前定义函数。

  1. # 下面的函数打印系统信息:
  2. print_distro_info() {
  3. echo "Here is the distro info:"
  4. uname -a
  5. }
  6. print_distro_info

函数也可以有参数,用\$1,$2得到,例如:

  1. discuss_languages(){
  2. languages1=$1
  3. languages2=$2
  4. echo "$1 is a good language."
  5. echo "$2 is also a good language."
  6. }
  7. discuss_languages c++ python

注意调用时,参数两边没有括号

  1. find_cpp_files(){
  2. local folder=$1
  3. local ret=$(find ${folder} -name '*.cpp' | wc -l)
  4. return $ret
  5. }
  6. folder=/ssd01/wanghuijiao
  7. find_cpp_files $folder
  8. num_files=$?
  9. echo "There are ${num_files} cpp files in ${folder}"
  1. #!/bin/bash
  2. # Experimenting with variable scope
  3. var_change(){
  4. local var1='local 1'
  5. echo "Inside function: var1=\"$var1\" var2=\"$var2\""
  6. var1='change again'
  7. var2='2 changed again'
  8. }
  9. var1='global 1'
  10. var2='global 2'
  11. echo "Before function call: var1=\"$var1\" var2=\"$var2\""
  12. var_change
  13. echo "After function call: var1=\"$var\" var2=\"$var2""

6. 调试技巧

  1. #!/bin/bash
  2. set -e
  3. mkdir ./tmp/data
  4. echo "Directory ./tmp/data was just created."
  5. # 输出
  6. mkdir:./tmp/data: File exists
  1. #!/bin/bash
  2. set -x
  3. floor=8th
  4. echo "A lot of power has been consumed at the ${floor} floor."
  5. # 输出
  6. + floor=8ths
  7. + echo 'A lot of power has been consumed at the 8th floor.'
  8. A lot of power has been consumed at the 8th floor.

注意:实际调试可以用bash -x或bash -e的方式来运行脚本,来达到set -x或者set -e 的效果。这样的好处时不需要改脚本。

习题

1. 找到本地的一个代码目录,统计里面.py文件个数.

2. 用下面的命令在\tmp目录生成一个脚本文件1.sh

3. 用下面的命令在/tmp目录中生成目录和文件

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注