Bash 在sh中操作参数

Bash 在sh中操作参数,bash,shell,scripting,sh,Bash,Shell,Scripting,Sh,我正在使用一个实用程序(,但这不是重点),它接受如下参数: $ unison -path path1 -path path2 -path path3 我想写一个sh脚本,我可以这样运行: $ myscript path1 path2 path3 $ echo abc | demo s/a/A/ s/b/B/ 我希望有一个兼容Posix的解决方案,但是特定于bash的解决方案也不错 我猜应该是这样的: #!/bin/sh unison ${*/ / -path } 但这不起作用 编辑:好的

我正在使用一个实用程序(,但这不是重点),它接受如下参数:

$ unison -path path1 -path path2 -path path3
我想写一个sh脚本,我可以这样运行:

$ myscript path1 path2 path3
$ echo abc | demo s/a/A/ s/b/B/
我希望有一个兼容Posix的解决方案,但是特定于bash的解决方案也不错

我猜应该是这样的:

#!/bin/sh
unison ${*/ / -path }
但这不起作用

编辑:好的,我想我得到了一些东西:

#!/bin/bash
PARAMS=
for arg in "$@"
do
    PARAMS+=" -path '$arg'"
done
unison $PARAMS

问题是这只在bash中有效,我很确定有更好的方法引用参数。

如果不选中,可以简单到:

exec unison -path $1 -path $2 -path $3
如果不在路径名中嵌入空格,则可以使用以下参数处理数量可变的参数:

arglist=""
for path in "$@"
do
    arglist="$arglist -path $path"
done
exec unison $arglist
如果路径名中有空格,则必须更加努力;我通常使用一个名为
escape
的自定义程序,它引用需要引用的参数和
eval

arglist=""
for path in "$@"
do
    path=$(escape "$path")
    arglist="$arglist -path $path"
done
eval exec unison "$arglist"
我注意到,使用Perl或Python会使处理带有空格的参数变得更容易——但问题是关于shell的


在Bash中使用shell数组变量也可能是可行的—将参数构建到一个数组中,并将数组作为参数传递给
unison
命令。

如果您想要一个高度特定于Bash的版本,可以尝试

#! /bin/sh eval eval exec \ unison -path\\ \\\"{$(eval echo \\\"\\\${1..$#}\\\" | sed 's/ /,/g')}\\\" #! /垃圾箱/垃圾箱 eval eval exec\ unison-path\\\\\“{$(eval echo\\\”\\\\${1..$\\\\\\\\\“\124; sed's//,/g')}\\” 如果删除所有带三个反斜杠引号的字符,这将更容易理解,但我不会因为解释它而破坏乐趣:-)


主要的复杂性是处理带有空格的文件名。这就解释了三重反冲报价和双重求值。

如果使用Bash的数组,所有报价问题都会消失

#!/bin/bash
args=()
for i in "$@"; do
    # With Bash >= 3:
    args+=(-path "$i")
    # +=() doesn't work in Bash 2
    # args=("${args[@]}" -path "$i")
done
exec unison "${args[@]}"

在Bash中,您可以使用
“${@/#/-path}”
将每个位置参数的开头替换为“-path”。要表示字符串的结尾,请使用
%
而不是
#

下面是一个使用
sed
和重复的
-e
选项的简单演示脚本。(当然有更有效的方法使用
sed

然后像这样运行它:

$ myscript path1 path2 path3
$ echo abc | demo s/a/A/ s/b/B/
我们得到:

Resulting arguments: -e s/a/A/ -e s/b/B/
ABc

以下是如何令人满意地引用您的角色:

job_strategy()
{
  local p
  for p in "$@"; do
    printf '-path\000%s\000' "$p"
  done
}

job_process()
{
  xargs -0 unison
}

job_strategy "path1" "path2" "path3" | job_process

您是否希望一个不涉及
for
循环的单行解决方案?引入单引号可能是个坏主意。正如所写的那样,unison命令可以看到引号,这不是您想要的。如果参数中没有任何单引号,则使用单引号保护参数的外部是可以的,但是您可能需要一个eval才能使其正常工作。这里很有意思——尽管不是所有的答案都适用于POSIX sh,但它对您提出的解决方案中存在的问题的解释是完全相关的。同上@Gordon,另外感谢您包含关于Bash 2兼容性的内容!世界跆拳道联盟?如果你想成为bash特定的人,正确的做法是使用数组——这样你就可以得到一个简单易读的代码,可以清楚地写出来明显没有bug,而不是依赖于没有明显的bug。这个答案是奇怪的、神秘的和幽默的,不是“正确的事情”的例子。也就是说,
xargs-0
POSIX?我的印象是它是一个GNU扩展。它没有在Uppps中列出,我错误地引用了FreeBSD手册页面:它应该是
POSIX.2