Linux Shell 语法

1. Linux Shell 语法

1.1. 如何查看 shell 是 zsh 还是 bash

echo $0

1.2. shbash 的区别

shbash 在语法方面还是有些区别的。当你遇到类似 [[: not found" 之类的错误的时候,就说明碰到这方面的问题了。

GNU/Linux 操作系统中的 /bin/sh 本是 bash (Bourne-Again Shell) 的符号链接,但鉴于 bash 过于复杂,有人把 bash 从 NetBSD 移植到 Linux 并更名为 dash (Debian Almquist Shell), 并建议将 /bin/sh 指向它,以获得更快的脚本执行速度。Dash Shell 比 Bash Shell 小的多,符合 POSIX 标准。

#!/bin/bash

#!/bin/sh

1.2.1. [[ is a bash builtin command and is not available in sh, same as ==

bash way:

readonly file1=1.txt
readonly file2=2.txt

if [[ $(diff $file1 $file2) == "" ]]
then
    echo "Identical files"
else
    echo "There are differences"
fi

sh way:

if [ "$(diff $file1 $file2)" = "" ]
then
    echo "Identical files"
else
    echo "There are differences"
fi

1.3. shell 魔法

1.3.1. !!

!! 代表了上一条执行的命令。可以看到,当输入两个感叹号时,它显示上条命令的同时会执行上一条命令。当然了,通常我们还会想到使用 “UP” 键来完成这个事情。但是如果是基于上条命令扩充,!! 就来得更加方便了。

比如,你想查看某个文件,但是忘了输入 more:

$ /opt/user/test.txt #忘记输入 more

$ more !! #这样是不是快多了?

使用 !! 是不是方便多了?

1.3.2. #!

#!/bin/sh是指此脚本使用/bin/sh来解释执行,#!是特殊的表示符,其后面根的是此解释此脚本的 shell 的路径。

其实第一句的#!是对脚本的解释器程序路径,脚本的内容是由解释器解释的,我们可以用各种各样的解释器来写对应的脚本。

比如说/bin/csh脚本,/bin/perl脚本,/bin/awk脚本,/bin/sed脚本,甚至/bin/echo等等。

#!/bin/bash同理。

It’s a convention so the *nix shell knows what kind of interpreter to run.

For example, older flavors of ATT defaulted to sh (the Bourne shell), while older versions of BSD defaulted to csh (the C shell).

Even today (where most systems run bash, the “Bourne Again Shell”), scripts can be in bash, python, perl, ruby, PHP, etc, etc. For example, you might see #!/bin/perl or #!/bin/perl5.

PS: The exclamation mark (!) is affectionately called “bang”. The shell comment symbol (#) is sometimes called “hash”.

PPS: Remember - under *nix, associating a suffix with a file type is merely a convention, not a “rule”. An executable can be a binary program, any one of a million script types and other things as well. Hence the need for #!/bin/bash.

The shebang is not a shell convention, it is interpreted by the kernel when handling the execve(2) syscall; so the shebang is a kernel convention, not a shell one.

1.4. 条件判断

1.4.1. 并且

条件:c1 并且条件 c2

  • 方式一:-a: and
if [ c1 -a c2 ]; then
    ....
fi
  • 方式二:&&: and
if [ c1 ] && [ c2 ]; then
    ....
fi

1.4.2. 或者

条件:c1 或者条件 c2

  • 方式一:-o: or
if [ c1 -o c2 ]; then
    ....
fi

方式二:||: or

if [ c1 ] || [  c2 ]; then
    ....
fi
a=0
b=1

if [ $a = 1 ] || [ $b = 1 ]; then
    echo "good"
fi

1.5. Bash Array – For Loop

1.5.1. For Each Element in Array

arr=( "apple" "banana" "cherry" )
 
for item in "${arr[@]}"
do
    echo $item
done

Output:

apple
banana
cherry

1.5.2. Iterate over Array Items using For Loop and Index

We take index and increment it in for loop until array length. During each iteration of the loop, we use the index to access the item in array.

arr=( "apple" "banana" "cherry" )
 
for (( i=0; i<${#arr[@]}; i++ ));
do
    echo ${arr[$i]}
done

Output:

apple
banana
cherry

1.6. How to split a string into an array in Bash?

1.6.1. Common Pitfalls

my_array=( $(command) )

Let’s take the seq command as an example and try if the above approach works:

$ seq 5
1
2
3
4
5
$ my_array=( $(seq 5) )
$ declare -p my_array
declare -a my_array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")
  1. Output May Contain Spaces
$ seq -f 'Num %g' 5
Num 1
Num 2
Num 3
Num 4
Num 5
$ my_array=( $(seq -f 'Num %g' 5) )
$ declare -p my_array
declare -a my_array=([0]="Num" [1]="1" [2]="Num" [3]="2" [4]="Num" [5]="3" [6]="Num" [7]="4" [8]="Num" [9]="5")

Let’s try if it can fix the problem:

$ IFS=$'\n'
$ my_array=( $(seq -f 'Num %g' 5) )
$ declare -p my_array
declare -a my_array=([0]="Num 1" [1]="Num 2" [2]="Num 3" [3]="Num 4" [4]="Num 5")
  1. Output May Contain Wildcard Characters
$ seq -f 'Num*%g' 5
Num*1
Num*2
Num*3
Num*4
Num*5

$ touch Number.app.log.{4..5}
$ ls -1
Number.app.log.4
Number.app.log.5

Now, let’s check if our solution can still convert the output into an array correctly:

$ my_array=( $(seq -f 'Num*%g' 5) )
$ declare -p my_array
declare -a my_array=([0]="Num*1" [1]="Num*2" [2]="Num*3" [3]="Number.app.log.4" [4]="Number.app.log.5")

1.6.2. Using the readarray Command

readarray is a built-in Bash command. It was introduced in Bash ver.4.

We can use the readarray built-in to solve the problem:

$ readarray -t my_array < <(seq 5)
$ declare -p my_array
declare -a my_array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")

$ readarray -t my_array < <(seq -f 'Num %g' 5)
$ declare -p my_array
declare -a my_array=([0]="Num 1" [1]="Num 2" [2]="Num 3" [3]="Num 4" [4]="Num 5")

$ ls -1
Number.app.log.4
Number.app.log.5

$ readarray -t my_array < <(seq -f 'Num*%g' 5)
$ declare -p my_array
declare -a my_array=([0]="Num*1" [1]="Num*2" [2]="Num*3" [3]="Num*4" [4]="Num*5")

1.6.3. Using the read Command

The Bash shell has another built-in command: read, it reads a line of text from the standard input and splits it into words.

We can solve the problem using the read command:

IFS=$'\n' read -r -d '' -a my_array < <( COMMAND && printf '\0' )

Let’s test it and see if it will work on different cases:

$ IFS=$'\n' read -r -d '' -a my_array < <( seq 5 && printf '\0' )
$ declare -p my_array
declare -a my_array=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")

$ IFS=$'\n' read -r -d '' -a my_array < <( seq -f 'Num %g' 5 && printf '\0' )
$ declare -p my_array
declare -a my_array=([0]="Num 1" [1]="Num 2" [2]="Num 3" [3]="Num 4" [4]="Num 5")

$ IFS=$'\n' read -r -d '' -a my_array < <( seq -f 'Num*%g' 5 && printf '\0' )
$ declare -p my_array
declare -a my_array=([0]="Num*1" [1]="Num*2" [2]="Num*3" [3]="Num*4" [4]="Num*5")

1.7. bash and sh mix error

  1. Syntax error: redirection unexpected.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

云满笔记

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

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

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

打赏作者

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

抵扣说明:

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

余额充值