62

我在 Linux 上制作了两个测试 bash 脚本以明确问题。

TestScript1 看起来像:
    echo "TestScript1 Arguments:"
    echo "$1"
    echo "$2"
    echo "$#"
    ./testscript2 $1 $2
TestScript2 看起来像:
    echo "TestScript2 Arguments received from TestScript1:"
    echo "$1"
    echo "$2"
    echo "$#"
当我以下列方式执行 testscript1 时:
    ./testscript1 "Firstname Lastname" testmail@domain.com  
所需的输出应该是:
    TestScript1 Arguments:  
    Firstname Lastname  
    testmail@domain.com  
    2
    TestScript2 Arguments received from TestScript1:  
    Firstname Lastname  
    testmail@domain.com  
    2  
但实际输出是:
    TestScript1 Arguments:  
    Firstname Lastname  
    testmail@domain.com  
    2
    TestScript2 Arguments received from TestScript1:  
    Firstname
    Lastname      
    3  

我该如何解决这个问题?我想获得所需的输出而不是实际输出。

4

4 回答 4

58

在 Testscript 1 中引用您的参数:

echo "TestScript1 Arguments:"
echo "$1"
echo "$2"
echo "$#"
./testscript2 "$1" "$2"
于 2013-06-07T16:07:22.420 回答
35

您需要使用 : "$@"(带引号)或"${@}"(相同,但也告诉 shell 变量名称的开始和结束位置)。

(并且不要使用 : $@, or "$*", or $*)。

前任:

#testscript1:
echo "TestScript1 Arguments:"
for an_arg in "$@" ; do
   echo "${an_arg}"
done
echo "nb of args: $#"
./testscript2 "$@"   #invokes testscript2 with the same arguments we received

我不确定我是否理解你的其他要求(你想用单引号调用'./testscript2'?)所以这里有2个疯狂的猜测(改变上面的最后一行):

'./testscript2' "$@"  #only makes sense if "/path/to/testscript2" containes spaces?

./testscript2 '"some thing" "another"' "$var" "$var2"  #3 args to testscript2

请给我你想要做的确切事情

编辑:在他的评​​论说他尝试 tesscript1 "$1" "$2" "$3" "$4" "$5" "$6" 运行: salt 'remote host' cmd.run './testscript2 $1 $2 $3 $4 $5 $6'

您有许多中间级别:主机 1 上的 testscript1,需要运行“salt”,并给它一个启动“testscrit2”的字符串,并带有引号中的参数......

您可以通过以下方式“简化”:

#testscript1

#we receive args, we generate a custom script simulating 'testscript2 "$@"'
theargs="'$1'"
shift
for i in "$@" ; do
   theargs="${theargs} '$i'"
done

salt 'remote host' cmd.run "./testscript2 ${theargs}"

如果这不起作用,那么不要运行“testscript2 ${theargs}”,而是将上面的最后一行替换为

echo "./testscript2 ${theargs}" >/tmp/runtestscript2.$$  #generate custom script locally ($$ is current pid in bash/sh/...)
scp /tmp/runtestscript2.$$ user@remotehost:/tmp/runtestscript2.$$ #copy it to remotehost
salt 'remotehost' cmd.run "./runtestscript2.$$" #the args are inside the custom script!
ssh user@remotehost "rm /tmp/runtestscript2.$$" #delete the remote one
rm /tmp/runtestscript2.$$ #and the local one
于 2013-06-07T16:43:33.957 回答
0

您可以执行以下操作来解析所有参数:

注意/bin/bash 的使用

测试脚本1:

#!/bin/bash

echo "TestScript1 Arguments:"
echo "$1"
echo "$2"
echo "$#"

# Build PARAMS to be a list of arguments
# Each wrapped in quotes and
# any existing quotes escapes with \
for var in "$@"
do
    PARAMS="$PARAMS \"${var//\"/\\\"}\""
done

# Call the second script with eval, also passing an extra parameter.
eval ./testscript2 "ExtraParam" $PARAMS

测试脚本2:

#!/bin/bash
echo "TestScript2 Arguments received from TestScript1:"
echo "$1"
echo "$2"
echo "$3"
echo "$#"

然后当您执行以下操作时:

./testscript1 "Firstname Lastname" testmail@domain.com  

输出将是:

TestScript1 Arguments:
Firstname Lastname
testmail@domain.com
2
TestScript2 Arguments received from TestScript1:
ExtraParam
Firstname Lastname
testmail@domain.com
3

通过以这种方式构建 PARAMS 使用\"${var//\"/\\\"}\""它允许脚本正确运行,即使在参数中使用引号调用,如下所示:

./testscript1 "Firstname's Last\"name" testmail@domain.com  

输出将是:

TestScript1 Arguments:
Firstname's Last"name
testmail@domain.com
2
TestScript2 Arguments received from TestScript1:
ExtraParam
Firstname's Last"name
testmail@domain.com
3

所有引号和空格都正确地从一个脚本传递到另一个脚本。

如果您不想传递所有参数,请忽略 for 循环,只需将 eval 与相关参数一起使用。

例如:

eval ./testscript2 "\"${1//\"/\\\"}\"" "Test1" "Test2" 

${1...表示第一个参数,${2...用于第二个等。

这将导致:

TestScript1 Arguments:
Firstname's Last"name
testmail@domain.com
2
TestScript2 Arguments received from TestScript1:
Firstname's Last"name
Test1
Test2
3

如果你确定你永远不会在参数中得到引号,那么不要"\"${1//\"/\\\"}\""只使用 use "$1"

于 2021-07-25T11:47:46.957 回答
-2

我发现以下程序对我有用

test1.sh 
a=xxx
test2.sh $a

在 test2.sh 你$1用来引用atest1.sh 中的变量

回声 $1

输出将是xxx

于 2015-01-12T22:01:25.700 回答