[shell] $@ 与 eval

$@ 与 $*

$@的用法以及与$*的区别可以参考 What does $@ mean in a shell script?

测试脚本如下

#!/bin/bash

set -e
set -x

bash -c $@
bash -c "$@"
bash -c $*
bash -c "$*"

一般情况下,我们可能会这样执行脚本

./test.sh Y=324 X=1 echo hello

输出如下,可见"$*"会把所有的参数包裹在单引号里作为一个完整的参数,这样bash -c才能正常运行。

+ bash -c Y=324 X=1 echo hello
+ bash -c Y=324 X=1 echo hello
+ bash -c Y=324 X=1 echo hello
+ bash -c 'Y=324 X=1 echo hello'
hello

然后我们这样执行一次脚本

./test.sh "Y=324" X=1 "echo hello"

输出如下,可以看出只有"$@"可以保证参数的一致性。如果这个脚本继续调用其他脚本,并切希望把参数继续传递下去,那么最好使用"$@"

+ bash -c Y=324 X=1 echo hello
+ bash -c Y=324 X=1 'echo hello'
+ bash -c Y=324 X=1 echo hello
+ bash -c 'Y=324 X=1 echo hello'
hello

eval

eval的作用是将其参数中的$再执行一次。测试脚本如下,两个\\是防止转义

#!/bin/bash

echo "args:"
for ((i = 0; i <= $#; i++)); do
    echo "    \$$i: \${$i}"
done
for ((i = 0; i <= $#; i++)); do
    eval "echo \"    \\\$$i: \${$i}\""
done

这样执行一次脚本

./test.sh "Y=324" X=1 "echo hello"

输出如下。

args:
    $0: ${0}
    $1: ${1}
    $2: ${2}
    $3: ${3}
args:
    $0: ./test.sh
    $1: Y=324
    $2: X=1
    $3: echo hello

常见例子

整一个高难度例子看看。

init.sh的内容如下

#!/bin/bash

exec 1>./logs/stdout.log
exec 2>./logs/stderr.log

set -e
set -x

echo "Do something here~"

exec bash ./entrypoint.sh "$@"

entrypoint.sh的内容如下

#!/bin/bash

exec 1>>./logs/stdout.log
exec 2>>./logs/stderr.log

set -e
set -x

echo "hello world!"

echo "args:"
for ((i = 0; i <= $#; i++)); do
    eval "echo \"    \\\$$i: \${$i}\""
done

exec bash -c "$*"

执行如下命令

chmod +x init.sh entrypoint.sh
./init.sh TP=4 PP=1 MBS=16 GBS=512 NLS=36 HS=4096 NAH=32 NNODES=16 SLEEP=10s bash ./entrypoint.sh echo byebye

查看stdout.log,打印出结果

Do something here~
hello world!
args:
    $0: ./entrypoint.sh
    $1: TP=4
    $2: PP=1
    $3: MBS=16
    $4: GBS=512
    $5: NLS=36
    $6: HS=4096
    $7: NAH=32
    $8: NNODES=16
    $9: SLEEP=10s
    $10: bash
    $11: ./entrypoint.sh
    $12: echo
    $13: byebye
hello world!
args:
    $0: ./entrypoint.sh
    $1: echo
    $2: byebye
byebye

你可能感兴趣的:(shell)