bash命令
一、Bash相关
1、运行Bash
(1)可以直接在命令行中运行,例如cd \xxx
(2)存储在脚本文件中执行,扩展名为.sh或者没有扩展名。
如果是用脚本文件运行:第一行写上#!/bin/bash;其中#!也叫做Shebang,另外还需要把该.sh文件设置为可执行文件。chmod +x
在计算领域中,Shebang是一个由井号和叹号构成的字符序列#!,其出现在文本文件的第一行的前两个字符。 在文件中存在Shebang的情况下,类Unix操作系统的程序加载器会分析Shebang后的内容,将这些内容作为解释器指令,并调用该指令,并将载有Shebang的文件路径作为该解释器的参数。
(3)bash脚本开头经常会有set -x参数,表示当有语句执行错误时,整个脚本能够停下来,而set -x命令表示在调试Bash脚本时,希望能够被执行的具体命令,而不仅仅是输出,因此常用set -xe
(4)bash命令行Terminal撤销输入 Ctrl+Shift±
2、变量
<variable>="value"
例如:des="sd"
注意=两边不能有空格!!
读取变量使用${variable}
例如:echo ${des}
如果读取的变量后面不是分隔符(回车),那么必须使用{}
例如:cp $filename ${des}_backup
否则系统会任务des_backup是一个变量
Bash中的单引号和双引号都表示字符串,但是双引号中的变量会展开,单引号不会。
例如:
s1='sds'
echo ${s1}
s2="333"
echo "${s2}dfdf"
echo '${s2}dfdf'
返回
sds
333dfdf
${s2}dfdf
双引号中使用$会将$按照原字符串输出。
3、内置变量
系统一些内置变量,例如$PATH 表示搜索可执行文件的路径列表
4、环境变量
运行python train.py
时会给进程设置环境变量CUDA_VISIBLE_DEVICES。
此时python train.py
只能看到0,1两块GPU,不能使用其他的GPU。
普通变量的赋值和export有什么区别?
直接在Shell中赋值的变量,子进程不可见,而用export赋值的变量,子进程可见。
或者在同一行先写变量赋值,在执行子进程,例如:some_var=kk python -c 'import os; import sys;print os.environ.get(sys.argv[1])' some_var
,这样子进程是可见的,而在下一个命令中是没有该变量的。
export some_var='kk'
python -c 'import os; import sys;print os.environ.get(sys.argv[1])' some_var # 这样整个本Shell周期内都是可见的。
5、source
source ./vars.sh
source后的脚本不再是新开的子shell运行,source使得vars.sh中的每一行,都像是在父Shell中执行一样。
6、输出赋值
可以用 ( c o m m a n d ) 把某个命令的输出赋值给某个变量例如: ‘ v a r 1 = (command)把某个命令的输出赋值给某个变量 例如:`var1= (command)把某个命令的输出赋值给某个变量例如:‘var1=(echo “sdsdsd”)`
7、运算let expr 双括号
let "a = 5+19"
echo a
返回24
let "b = 13*14"
expr会把表达式的结果输出,比如:
expr 5 * 19
!!!注意必须有空格才能当作表达式,否则就跟字符串一样的。
foo=$(expr 5 + 8)
!! 注意*号貌似会返回当前目录的所有文件和文件夹,+号是可以的,但是需要有空格。
双括号。
8、if判断语句
if <condition>
then
<cmd>
else
<cmd>
fi
else语句可以省略。
例如:
if [ ${temp} -ge 30] # -ge的意思是大于等于greate or equ。注意-ge前面只能有一个表达式,不能${a} + ${b} -ge 3
then
echo "sadsad"
fi
【注意这里的if内部语句前后必须有空格。】
if [ -e /bin/ls ] # 判断文件是否存在
then
echo "oko"
fi
还有很多其他的计算表达式
上述表达式可以使用单独的命令test来判断
test 5 -ge 4 #
echo $? # $?是上一个语句的返回结果,是上一个语句!如果上一个语句报错了,那么返回值会被更新成错误的
test 5 -ge 2 && echo "Condition is true" || echo "Condition is false"
,test命令常用于条件测试,其结果不会被直接输出,需要用逻辑判断来检查返回值
如果有多重判断,中间需要使用elif而不是else!!!,Bash的if语句可以嵌套
if判断是否存在某个文件夹
if [ ! -d "$output_folder" ]
# 如果不存在该文件夹
9、布尔运算
运算表达式可以用布尔运算连接起来,比如&&或||
if [ $code_review = "pass" ] && [ $regression_test = "pass" ]
# 注意多个表达式需要多个[]之间用布尔运算,而不是一个[]
10、for循环语句 for do done,while循环语句
for x in 1 2 3 44 5
do
echo ${x} # 不要忘了$
done
对于数字1-n的循环,Bash有一个内置的写法{1…n}
for i in {1...3}
do
echo $i
done
也有类似C语言中for循环的写法:
for((i=1; i<3; i++))
do
echo $i
done
注意可以遍历一个字符串,以空格分隔每个字符串,这个很重要
checkpoint_path="checkpoints"
checkpoint_name="aaa bbb ccc ddd eee fff"
datasets_name="COCO"
for ckpt in ${checkpoint_name}; do
echo -ne "${ckpt}:\t" >> ${log_name} # 追加而不覆盖
for dataset in ${datasets_name}; do
bash /mnt/abs.sh "/mnt/${dataset}/cost.result" >> ${log_name}
done
echo "" >> ${log_name}
done
while循环语句
while read jpg_file; do
# 读取每一行的路径,并赋值给jpg_file变量
11、until语句 until do done
until [ ! -e "foo${suffix}" ] # 直到不存在该文件名
do
let suffix++
done
12、break、continue
在循环过程中可以中途退出,或者立刻运行下一次循环。
13、函数
必须在调用前定义函数
function_name() { # 注意这里的函数名后面一定要有()
<command>
}
# 或者
function function_name {
<commands>
}
在函数里,可以用return返回结果。Shell函数的返回值只能是介于0-255之间的整数。
find_cpp_files() {
local folder="/home/tieshuai.song/"
local ret=$(find ${folder} -name "*.stdout" | wc -l)
echo $ret
return $ret
}
find_cpp_files # 这里的调用函数不需要有()
echo $? # 返回上一步的计算结果
14、scope全局变量
var_change () {
local var1='local 1'
echo "Inside function : var1=\"$var1\" var2=\"$var2\""
var1='changed again'
var2='2 changed again'
}
15、调试技巧set
注意:实际调试可以用bash -x或者bash -e的方式运行脚本, 来达到set -x或者set -e的效果。 这样的好处是不需要改脚本。
程序开头设置如下,能够在碰到异常情况时停止执行。
set -x # 用于启用脚本的调试模型,会使得脚本执行时将每个要执行的命令显示出来
set -e # 命令执行不成功(返回值非0)会中断,停止运行
set -u # 使用未定义的变量中断
set -o pipefail # 一个管道复合命令,只要有其中一个fail,整个命令就算fail
16、Bash随机数相关
使用$RANDOM
变量以及取余运算符%来限制范围
random_number=$((1 + $RANDOM % 100))
# 这里如果直接用random_number=RANDOM % 100,bash会将其解释为字符串赋值,而不是取余操作,正确的操作是执行$((...))
来进行算术运算。
17、Bash算术运算
Bash脚本中使用 $((...))
来进行算术运算,使用-eq
来表示等于
例如下面打印1-100以内的素数
#!/bin/bash
isPrime=1
for((i=2; i<=100; i++))
do
# if Prime?
for((j=2; j*j<=i; j++))
do
if [ $((i % j)) -eq 0 ]; then # isPrime
isPrime=0
break;
fi
done
if [ $isPrime -eq 0 ]; then
isPrime=1
continue
else
echo $i
fi
done
二、Bash基础知识
1、echo:
echo "dsd"
把参数输出到屏幕,并且有回车,这点跟printf
不一样,printf "sd"
输出最后没有回车
也就是echo
默认会输出一个new line,而printf
不会
echo sdsd
也可
echo -e
中-e选项是用来激活echo命令的转义字符(以\开头的例如\n换行)功能,这个很重要
echo 1111 >> a_file
将1111写入文件a_file中,如果不存在就创建这个文件
echo
默认是带回车的,如果不希望有回车,使用echo -n abccd
类似的-n命令
2、printf
printf "sdsd
" 最后没有回车
printf sdssd
也是
printf
和C语言中的printf
类似,格式化输出
printf "i and you %d\n" 33
3、stdout和stderr
stdout
和stderr
: 程序的输出包括stdout
和stderr,默认都会输出到终端屏幕上
echo “sds” > /tmp/ls.stdout可以把stdout输出到文件里面,内容为sds # 单个>
ls > /tmp/ls.stdout把ls返回的内容输出到终端上
ls 1> /tmp/ls.stdout 2> /tmp/ls.stderr # stdout输出到ls.stdout,stderr输出搭配ls.stderr
ls &> /tmp/ls.stdall # 都保存到同一文件
## rev把输入颠倒输出
```bash
rev # 先输入rev然后回车,输入👇
rev echo "sdssdsdddddd" # 按回车后返回"ddddddsdssds" ohce ver
# 但是此时程序并没有结束,人工按Ctrl+D结束输入,再按一次会退出命令行
4、| && || bash组合命令
|
echo yitutech | rev
会把多个命令组合起来,前一个命令的输出会变成后一个命令的输入,返回hcetutiy,一定要和||区分开
&&
程序依次执行命令,如果前一个命令报错(返回值不为0)则不执行后续的命令,echo "sds" && ls
||
前一个命令不成功,则后一个才会执行
$() 命令嵌入,可以把某一命令的输出赋给某一变量
把某个命令的输出嵌入到另一个命令中,例如echo $(seq 1 3)
返回 1 2 3。【】seq 1 3是产生1-3的序列
checkpoint_name=$(find ${checkpoint_path} -type f -name "*embed*" | grep -oP '([^\/]*)\.[^\/]*$' | sed 's/\..*//' | sort | xargs)
() 把多个命令的输出统一到某文件
当()内部多个命令,可以统一管理这些命令的输出 (echo sdsd ; ls; echo "ecccccc") > output.txt
不同命令之间用;分隔
5、Bash获取命令行参数
$1, $2, $3分别表示第一个,第二个,第三个…命令行参数,$0为bash命令本身
echo "first is $1"
获取所有的命令行参数:"$@"
echo "$@"
获取命令行参数的个数:"$#"
echo “$#”