符合POSIX标准的shell中的数组

zoo*_*oom 9 arrays bash posix dash-shell

根据hyperpolyglot.org上的参考表,可以使用以下语法来设置数组.

i=(1 2 3)
Run Code Online (Sandbox Code Playgroud)

但我得到一个错误的破折号/bin/shUbuntu 的默认值,应该符合POSIX标准.

# Trying the syntax with dash in my terminal
> dash -i
$ i=(1 2 3)
dash: 1: Syntax error: "(" unexpected
$ exit

# Working fine with bash
> bash -i
$ i=(1 2 3)
$ echo ${i[@]}
1 2 3
$ exit
Run Code Online (Sandbox Code Playgroud)

参考表是误导性的还是错误的?
如果是,那么定义数组或列表并且符合POSIX的正确方法是什么?

Kus*_*nda 11

这是真实的,POSIXsh外壳没有名为在同样的意义,数组bash和另一个外壳有,但有一个列表sh贝壳(以及bash和其他人)可以使用,这是列表中位置参数

此列表通常包含传递给当前脚本或 shell 函数的参数,但您可以使用set内置命令设置其值:

#!/bin/sh

set -- this is "a list" of "several strings"
Run Code Online (Sandbox Code Playgroud)

在上面的脚本中,位置参数$1, $2, ... 被设置为显示的五个字符串。将--用于确保您不会意外地设置一个shell选项(该set命令也能做到)。如果第一个参数以-尽管开头,这只是一个问题。

例如,循环遍历这些字符串,您可以使用

for string in "$@"; do
    printf 'Got the string "%s"\n' "$string"
done
Run Code Online (Sandbox Code Playgroud)

或者更短的

for string do
    printf 'Got the string "%s"\n' "$string"
done
Run Code Online (Sandbox Code Playgroud)

要不就

printf 'Got the string "%s"\n' "$@"
Run Code Online (Sandbox Code Playgroud)

set 也可用于将 glob 扩展为路径名列表:

#!/bin/sh

set -- "$HOME"/*/

# "visible directory" below really means "visible directory, or visible 
# symbolic link to a directory".

if [ ! -d "$1" ]; then
    echo 'You do not have any visible directories in your home directory'
else
    printf 'There are %d visible directories in your home directory\n' "$#"

    echo 'These are:'
    printf '\t%s\n' "$@"
fi
Run Code Online (Sandbox Code Playgroud)

shift内置命令可以用于在第一位置参数从列表中移离。

#!/bin/sh

# pathnames
set -- path/name/1 path/name/2 some/other/pathname

# insert "--exclude=" in front of each
for pathname do
    shift
    set -- "$@" --exclude="$pathname"
done

# call some command with our list of command line options
some_command "$@"

Run Code Online (Sandbox Code Playgroud)

  • @Lassi 在开头添加:`set -- "$item" "$@"`。要在末尾添加:`set -- "$@" "$item"`。您无法轻松删除“$@”的最后一个元素,但可以使用“shift”删除第一个元素。堆栈可以通过压入/弹出第一个元素来实现。 (3认同)

ric*_*ici 9

Posix不指定数组,因此如果限制为Posix shell功能,则不能使用数组.

我担心你的引用是错误的.可悲的是,并非您在互联网上找到的所有内容都是正确的.

  • @zoom 佛罗里达州沼泽地的供应商还提供详细而精确的调查报告。 (2认同)

Kar*_*hai 7

正如rici所说,破折号没有阵列支持.但是,如果您要做的是编写循环,则有一些解决方法.

For循环不会执行数组,但您可以使用while循环+ read内置来进行拆分.由于内置的​​破折号也不支持分隔符,因此您也必须解决这个问题.

这是一个示例脚本:

myArray="a b c d"

echo "$myArray" | tr ' ' '\n' | while read item; do
  # use '$item'
  echo $item
done
Run Code Online (Sandbox Code Playgroud)

对此有一些更深入的解释:

  • "tr'''\n'"将允许您在删除空格并添加换行符时执行单字符替换 - 这是读取内置函数的默认分隔符.

  • 当检测到stdin已经关闭时,"read"将以失败的退出代码退出 - 这将是您的输入已完全处理的时间.

  • 由于echo在输入后打印了一个额外的换行符,因此可以处理数组中的最后一个"元素".

这相当于bash代码:

myArray=(a b c d)

for item in ${myArray[@]}; do
  echo $item
done
Run Code Online (Sandbox Code Playgroud)

如果你想检索第n个元素(比如说例子的第2个):

myArray="a b c d"

echo $myArray | cut -d\  -f2 # change -f2 to -fn
Run Code Online (Sandbox Code Playgroud)

  • 问题在于它试图在一个字符串中存储多个单独的字符串。一旦您想要存储包含空白字符的字符串,您将无法正确检索它们。您必须使用空格以外的其他安全分隔符,然后实现您自己的字符串解析。 (2认同)