shell编程 (2) —— 基础

本文详细介绍了Shell编程的基础,包括for循环、变量操作、字符串处理、数组、注释、文件描述符、输入输出重定向以及分支、函数等。通过具体的练习如二分查找、快速排序和Codingame游戏解决方案,帮助读者巩固和应用Shell编程知识。
摘要由CSDN通过智能技术生成

shell 语法

for循环

#!/bin/bash
for language in c c++ java python shell_script; do
    echo "my ${language} skill is good."    #变量左右加上{}
done

变量

变量的二次赋值
#!/bin/bash
name="Elena"   # = 左右不能有空格
echo "hello, my name is ${name}"
name="Demon"   
echo "hello, my name is ${name}"
删除变量
str="Hello World!"
unset str    #删除变量   本程序没有任何的输出
echo ${str}
只读变量 【 不能更改,不能删除】
str="Hello World!"
readonly str
str="haha"   # /usercode/file.sh: line 4: str: readonly variable
unset str    # /usercode/file.sh: line 4: unset: str: cannot unset: readonly variable

引号

单双引号区别

单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
单引号字串中不能出现单引号(对单引号使用转义符后也不行)。

双引号里可以有变量
双引号里可以出现转义字符

反引号的使用

反引号”`”可以将指令括起来,然后交给shell

for file in `ls `; do
file ${file}
done

字符串部分

连接
#!/bin/bash
name="linux"
str="I love ${name}"
echo $str
str="I love "${name}
echo $str
字符串的长度
#!/bin/bash
str='Hello World!'
echo ${#str}   #12

或者使用expr工具 (evalution expression)

#!/bin/bash
str="Hello World!"
echo `expr length "${str}"`
字符串的截取
#!/bin/bash
str='Hello World!'
echo ${str:6:6}  #截取第7个字符后的长度是6的字符串   World!
查找字符

expr 可以用于模式匹配。它有一种用法:index string char 用于求解char在string中的位置,记住是从1开始的,如果不存在相应的字符,那么我们返回0.

#!/bin/bash
str="I love linux"
echo `expr index "${str}" love`

数组

#!/bin/bash
array=("C" "C++" "java" "python" "shell script")
echo ${array[@]}   #输出所有的元素
echo ${#array[@]}   #输出数组的长度

注释

单行注释是”#”
shell中没有像C那样方便的多行注释,只能一行一行的添加#,不过我们也可以将需要多行注释的地方写成一个函数,想要使用的时候加上就行。

3个fd

从shell中运行一个进程,默认会有3个文件描述符存在(0、1、2), 0与进程的标准输入相关联,
1与进程的标准输出相关联,2与进程的标准错误输出相关联,一个进程当前有哪些打开
的文件描述符可以通过/proc/进程ID/fd目录查看.

shell处理参数

参数处理说明
$#传递到脚本的参数个数
$*以一个单字符串显示所有向脚本传递的参数
$$脚本运行的当前进程ID号
$!后台运行的最后一个进程的ID号
$@与$*相同,但是使用时加引号,并在引号中返回每个参数
$-显示Shell使用的当前选项,与set命令功能相同
$?显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误

数值计算

利用工具expr可以实现数值计算。比如:

val=`expr 2 \* 4`
echo "calculate 2 * 4: "${val}    

关系运算符

运算符 说明 举例
-eq 检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 false。
-ne 检测两个数是否相等,不相等返回 true。 [ $a -ne $b ] 返回 true。
-gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false。
-lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。
-ge 检测左边的数是否大于等于右边的,如果是,则返回 true。 [ $a -ge $b ] 返回 false。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ $a -le $b ] 返回 true。

布尔运算符

operatormeaning
!
-o
-a
str="I love linux"
length=`expr length "${str}"`
if [ ${length} -gt 20 -o ${length} -lt 0 ]; then 
echo "this is bad string"
elif [ ${length} -lt 20 -a ${length} -gt 10 ]; then
echo "the length > 10 and < 20"
fi

逻辑运算符

operatormeaning
||
&&
str="I love linux"
length=`expr length "${str}"`
if [[ ${length} -gt 20 || ${length} -lt 0 ]]; then 
echo "this is bad string"
elif [[ ${length} -lt 20 && ${length} -gt 10 ]]; then
echo "the length > 10 and < 20"
fi

逻辑与、或和布尔与、或在形式上的差别是逻辑的if多了一对[]

字符串运算

#!/bin/bash
s1="jordan"
s2="james"
if [ $s1 = $s2 ]; then   #字符串相等
echo "s1 = s2"
fi

if [ $s1 != $s2 ]; then  #字符串不相等
echo "s1 != s2"
fi

if [ -n $s1 ]; then   #字符串非空
echo "the length of s1 is not zero"
fi 

if [ -z $s1 ]; then
echo "the length of s1 is zero"   #字符串为空
fi 

if [ $s2 ]; then
echo "the s2 is not empty"  #字符串非空
fi

# output:
# s1 != s2
# the length of s1 is not zero
# the s2 is not empty

文件测试运算符

操作符 说明 举例
-b file 检测文件是否是块设备文件,如果是,则返回 true。 [ -b $file ] 返回 false。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。 [ -c $file ] 返回 false。
-d file 检测文件是否是目录,如果是,则返回 true。 [ -d $file ] 返回 false。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。 [ -f $file ] 返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。 [ -g $file ] 返回 false。
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。 [ -k $file ] 返回 false。
-p file 检测文件是否是有名管道,如果是,则返回 true。 [ -p $file ] 返回 false。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。 [ -u $file ] 返回 false。
-r file 检测文件是否可读,如果是,则返回 true。 [ -r $file ] 返回 true。
-w file 检测文件是否可写,如果是,则返回 true。 [ -w $file ] 返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。 [ -x $file ] 返回 true。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。 [ -s $file ] 返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。 [ -e $file ] 返回 true。
#!/bin/bash
cd /tmp
pwd
touch myfile

if [ -e $myfile ]; then  #检测存在   
   echo "myfile exit"
   if [ -b $myfile ]; then   #块设备
   echo "myfile is block file"
   elif [ -c $myfile ]; then   #字符设备
   echo "myfile is character file"
   elif [ -f $myfile ]; then   #普通文件
   echo "myfile is normal file"
   elif [ -d $myfile ]; then  #路径
   echo "myfile is a dir"
   fi

   if [ -r $myfile ]; then   #读,写,可执行属性
   echo "myfile can be read"
   fi
   if [ -w $myfile ]; then
   echo "myfile can be wrote"
   fi
   if [ -x $myfile ]; then
   echo "myfile can be excuted"
   fi
fi 

输入和输出

read 从标准输入读取一行,赋予相应的变量
echo -e开启转义功能

echo:

echo -e "this is a story about hero.\n"  #没有-e, 就没有多一行
echo "end"

echo -e "this is a story about hero." #正常换行
echo "end"

echo -e "this is a story about hero.\c" #不换行
echo "end"

printf:
printf 和C里面的printf()相似。printf format-string [arguments…]

#!/bin/bash
printf "Hello World\n"
printf "%s %d\n" Jordan 23
name="Jordan"
age=23
printf "%s %d\n" $name $age

关于分支

在shell编程(1)的基础上增加一些补充。
bash里的分支不能是空的。
case分支:

case value in
mod1)
    command1
    command2
    ...
    commandN
    ;;
mod2)
    command1
    command2
    ...
    commandN
    ;;
esac

比如:

echo "enter a number: "
read number
case $number in
1)
   echo "you enter 1."
   ;;
2)
   echo "you enter 2."
   ;;
esac

函数

声明

下面[]中的function 可有可无。

[ function ] funname [()]
{
    action;
    [return int;]
}
参数

在函数的内部,我们可以使用$n来获取第n个参数的值。在函数外部,函数的返回值则可以通过$?来获得.

func(){
     echo "first arg is "$1;
     echo "second arg is "$2;
     return $(($1 + $2));
}
func 3 4
echo "the sum of two args is "$?

output:

first arg is 3
second arg is 4
the sum of two args is 7

其他参数

参数 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

输入输出重定向

文件描述符 0对应标准输入(STDIN),1 对应标准输出(STDOUT),2对应标准错误输出(STDERR)。

command > file #stdout 重定向到 file
command < file #stdin 重定向到 file
command > file file1>&file2 #将输出文件file2file1合并后重定向到file

例子:

#func.sh:
func(){
     echo "first arg is "$1;
     echo "second arg is "$2;
     return $(($1 + $2));
}
func 3 4
echo "the sum of two args is "$?
func();

#正常执行:
./func.sh
first arg is 3
second arg is 4
the sum of two args is 7
./func.sh: line 8: syntax error near unexpected token `;'
./func.sh: line 8: `func();'

#将标准输出和标准错误合并到文件read中:
./func.sh > read 2>&1

特殊的重定向:

command << delimiter
    document
delimiter

将两个 delimiter 之间的内容作为输入传递给 command。

练习

二分查找

  array=(10 20 30 40 50 60 70 80 90 100)
  bsearch(){
      l=0
      r=9
      ans=-1
      while (( $l <= $r )); do
          mid=`expr $(( $l + $r )) / 2`
          if [[ ${array[$mid]} -lt $1 ]]; then
              l=`expr $mid + 1`
          elif [[ ${array[$mid]} -eq $1 ]]; then
              ans=$mid
              break
          else
              r=`expr $mid - 1`
          fi
      done
      #return $ans
  }
  while true; do
      echo "enter a key number to find, -1 will kill program."
      read key
      if [ $key -eq -1 ]; then
      break
      fi
      bsearch key
      if [ $ans -eq -1 ]; then
      echo "not found."
      else
      echo "the index of key is "$ans
      fi
  done
enter a key number to find, -1 will kill program.
23
not found.
enter a key number to find, -1 will kill program.
30
the index of key is 2
enter a key number to find, -1 will kill program.
10
the index of key is 0
enter a key number to find, -1 will kill program.
100
the index of key is 9
enter a key number to find, -1 will kill program.
2244
not found.
enter a key number to find, -1 will kill program.
50
the index of key is 4
enter a key number to find, -1 will kill program.
-1

快速排序

#!/bin/bash
array=(1 5 3 9 4 8 6 2 7 10)
partion(){
    i=$1;  j=$2
    tmp=${array[$1]}
    while [[ $i -lt $j ]]; do
        while [[ $i -lt $j && ${array[$j]} -ge $tmp ]]; do
            j=`expr $j - 1`
        done
        array[$i]=${array[$j]}
        while [[ $i -lt $j && ${array[$i]} -le $tmp ]]; do
            i=`expr $tmp + 1`
        done
        array[$j]=${array[$i]}
    done
    array[$i]=$tmp
    return $i
}
quick_sort(){
    if [ $1 -lt $2 ]; then
        partion $1 $2
        mid=$?
        quick_sort $1 $mid
        quick_sort `expr $mid + 1` $2
    fi
}
quick_sort 0 9
echo "${array[@]}"

codingame之飞行着陆

飞行着陆
https://www.codingame.com/ide/60414612a754befc323b355d422a6bda40d80b1
大意:每一次削低最高的山峰,避免飞行器撞上山峰。
分析:每一次找出最高的山峰即可。

while true; do
    max_h=-1
    ans=0
    for (( i=0; i<8; i++ )); do
        # mountainH: represents the height of one mountain.
        read mountainH
        if [ ${max_h} -lt ${mountainH} ]; then
        ans=$i;
        max_h=${mountainH}
        fi
    done
    # Write an action using echo
    # To debug: echo "Debug messages..." >&2

    echo ${ans} # The index of the mountain to fire on.
done

codingame之reach the light of power

reach the light of power
https://www.codingame.com/ide/60438073859e8a8584667f65ae250e0beea41fb
大意:游戏人物从初始位置需要走到power位置,每一次可以转身,上、下、左、右、斜一共8个方向的转向选择,在给定转身次数的情况下输出转身方向。
分析:向量判断,就近原则。

# Auto-generated code below aims at helping you parse
# the standard input according to the problem statement.
# ---
# Hint: You can use the debug stream to print initialTX and initialTY, if Thor seems not follow your orders.

# lightX: the X position of the light of power
# lightY: the Y position of the light of power
# initialTX: Thor's starting X position
# initialTY: Thor's starting Y position
read lightX lightY initialTX initialTY

# game loop
while true; do
    # remainingTurns: The remaining amount of turns Thor can move. Do not remove this line.
    read remainingTurns

    # Write an action using echo
    # To debug: echo "Debug messages..." >&2


    # A single line providing the move to be made: N NE E SE S SW W or NW
    dx=`expr $lightX - $initialTX`
    dy=`expr $lightY - $initialTY`

    if [ $dx -gt 0 -a $dy -gt 0 ]; then
    string="SE"
    initialTX=`expr $initialTX + 1`
    initialTY=`expr $initialTY + 1`
    elif [ $dx -gt 0 -a $dy -eq 0 ]; then
    string="E"
    initialTX=`expr $initialTX + 1`
    elif [ $dx -gt 0 -a $dy -lt 0 ]; then
    string="NE"
    initialTX=`expr $initialTX + 1`
    initialTY=`expr $initialTY - 1`
    elif [ $dx -eq 0 -a $dy -lt 0 ]; then
    string="N"
    initialTY=`expr $initialTY - 1`
    elif [ $dx -lt 0 -a $dy -lt 0 ]; then
    string="NW"
    initialTX=`expr $initialTX - 1`
    initialTY=`expr $initialTY - 1`
    elif [ $dx -lt 0 -a $dy -eq 0 ]; then
    string="W"
    initialTX=`expr $initialTX + 1`
    elif [ $dx -lt 0 -a $dy -gt 0 ]; then
    string="SW"
    initialTX=`expr $initialTX - 1`
    initialTY=`expr $initialTY + 1`
    elif [ $dx -eq 0 -a $dy -gt 0 ]; then
    string="S"
    initialTY=`expr $initialTY + 1`
    else break
    fi

    echo $string
done
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值