如何将 bash 脚本参数传递给子 shell

如何将 bash 脚本参数传递给子 shell

我有一个包装脚本,它可以执行一些工作,然后将原始参数传递给另一个工具:

#!/bin/bash
# ...
other_tool -a -b "$@"

除非“其他工具”在子 shell 中运行,否则这可以正常工作:

#!/bin/bash
# ...
bash -c "other_tool -a -b $@"

如果我像这样调用包装器脚本:

wrapper.sh -x "blah blup"

然后,只有第一个原始参数 (-x) 被传递给“other_tool”。实际上,我没有创建子 shell,而是将原始参数传递给 Android 手机上的 shell,这应该没有什么区别:

#!/bin/bash
# ...
adb sh -c "other_tool -a -b $@"

答案1

Bash 的printf命令具有对字符串进行引用/转义/其他操作的功能,因此只要父 shell 和子 shell 实际上都是 bash,就可以这样工作:

[编辑:正如 siegi 在评论中指出的那样,如果你以显而易见的方式执行此操作,则在没有提供任何参数时会出现问题,它表现得好像实际上只有一个空参数。我在下面添加了一个解决方法,用 包装格式字符串${1+},其中仅包含格式字符串如果第一个参数已定义。这有点像临时解决办法,但确实有效。]

#!/bin/bash

quoted_args="$(printf "${1+ %q}" "$@")" # Note: this will have a leading space before the first arg
# echo "Quoted args:$quoted_args" # Uncomment this to see what it's doing
bash -c "other_tool -a -b$quoted_args"

请注意,您也可以在一行中完成此操作:bash -c "other_tool -a -b$(printf "${1+ %q}" "$@")"

答案2

这些解决方案都不太管用。只需将 x/\ \ \"b\"/aaaaa/\'xxx\ yyyy\'/zz\"offf\" 作为参数传递,它们就会失败。

这是一个处理所有情况的简单包装器。请注意它如何对每个参数进行两次转义。

#!/usr/bin/env bash
declare -a ARGS
COUNT=$#
for ((INDEX=0; INDEX<COUNT; ++INDEX))
do
    ARG="$(printf "%q" "$1")"
    ARGS[INDEX]="$(printf "%q" "$ARG")"
    shift
done

ls -l ${ARGS[*]}

答案3

它失败了,因为你正在将一个数组(位置参数)强制转换为一个字符串。"$@"这很神奇,因为它将每个单独的参数作为正确引用的字符串提供给你。添加额外的文本会破坏这种魔力:"blah $@"只是一个字符串。

这可能会让你更接近:

cmd="other_tool -a -b"
for parm in "$@"; do cmd+=" '$parm'"; done
adb sh -c "$cmd"

当然,任何包含单引号的参数都会引起麻烦。

答案4

好的,更多解释:

$ cat /tmp/test.sh
#! /bin/bash

echo '$@='"$@"

set -v # "debug"

sh -c 'echo $@' "$@" # gremlins steal the first option

sh -c 'echo $@' -- "$@" # We defend the option with two knifes

$ bash -e /tmp/test.sh first second third
$@=first second third

sh -c 'echo $@' "$@" # gremlins steal the first option
second third

sh -c 'echo $@' -- "$@" # We defend the option with two knifes
first second third

相关内容