破折号:将字符串解析为两个变量

Mar*_*ter 2 dash shell-script

我有一个破折号脚本,我需要解析$1,它是一个包含由 ' :'分隔的两部分的字符串,例如foo:123. 我想存入foo$X 和123$Y。

我以为我可以使用read

$ echo "foo:123" | tr ':' ' ' | read X Y
Run Code Online (Sandbox Code Playgroud)

但这不起作用(没有给出错误)

$ echo $X
Run Code Online (Sandbox Code Playgroud)

给出空行作为输出。

为什么我的read构造不起作用?我怎样才能实现我的目标(任何解决方案,都不必使用读取)

cuo*_*glm 7

dash 中管道中的 每个命令都在子shell运行zsh而 AT&T ksh管道中最右边的命令不是),因此当您的命令完成时,变量XY不再存在。

简单地说,您可以使用Parameter Expansion,尝试:

$ set -- foo:123
$ X=${1%:*}
$ Y=${1#*:}
Run Code Online (Sandbox Code Playgroud)

该示例用于交互式会话。

在您的脚本中,您不需要set -- foo:123.

  • 它们不必在子外壳中运行。除了一个都必须在子shell中运行。在 AT&T ksh 或 zsh 中,最右边的没有。在 bash 和 dash 中,它们都在子 shell 中运行。 (2认同)

Sté*_*las 5

您还可以使用split+glob运算符(将变量不加引号)(并且您在问题中没有明显原因使用它):

IFS=:     # configure the split part to use : as the delimiter
set -f    # disable the glob part
set -- $1 # $1 is split on : and parts are stored in $1, $2...
X=$1 Y=$2
Run Code Online (Sandbox Code Playgroud)

您还可以这样做:

printf '%s\n' "$1" | {
  IFS=: read -r X Y
  printf '%s\n' "$X"
}
Run Code Online (Sandbox Code Playgroud)

就像(但与 AT&T或相反)dash一样,管道的所有部分都在子 shell 中运行(它们无论如何都需要在不同的进程中运行,因为它们是同时运行的)。上面,我们需要将使用它的部分放在读取和设置的输出的子 shell 中。bashkshzsh$Xprintf $X

$1请注意,如果包含换行符或多个字符,这两种解决方案的行为会有所不同: