如何在bash中读取可变数量的变量

Ram*_*ety 2 bash for

我想从命令行读取一些字符串并在 loo 中读取所有字符串。如何在循环中进一步处理(如打印)它们。对不起,我是新手,请原谅我的新手问题。

#!/usr/bin/bash


echo "Enter the number of names of students"
read classcount

for ((i=1;i<=classcount;i++)); do
    read names[${i}]
done

for ((i=1;i<=classcount;i++)); do
    echo $names[${i}]
done
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 5

通常,最好避免脚本中的用户交互或从命令行使用的任何实用程序,因为它会阻碍自动化。

例如,您调用rm file1 file2 'file 3',而不rm只是期望它询问您要删除的文件数,然后分别提示每个文件。

同样,在这里,从命令行参数中获取学生列表会好得多:

#! /usr/bin/bash -
classcount=$#
names=("$@")

if (( classcount > 0 )); then
  echo "Student${name[1]+s}:"
  printf ' - %s\n' "${name[@]}"
fi
Run Code Online (Sandbox Code Playgroud)

并调用为:

that-script 'John Doe' 'Alice Smith' ...
Run Code Online (Sandbox Code Playgroud)

或者,例如从文本文件中每行获取一个学生列表(假设为 GNU xargs):

xargs -d '\n' -a student.list that-script
Run Code Online (Sandbox Code Playgroud)

您也可以从标准输入中每行读取一个,但最好没有交互并阅读列表直到输入结束,而不是先提示用户进行计数:

#! /usr/bin/bash -

readarray -t names
classcount="${#names[@]}"

if (( classcount > 0 )); then
  echo "Student${name[1]+s}:"
  printf ' - %s\n' "${name[@]}"
fi
Run Code Online (Sandbox Code Playgroud)

如果 stdin 是终端,则用户将用 表示输入结束Ctrl+D。

要从文件中获取列表:

that-script < student.list
Run Code Online (Sandbox Code Playgroud)

read可用于从 stdin 读取一行,但语法是IFS= read -r lvalue,而不是read lvalue。

另请注意,这[...]是一个通配符,因此应该被引用以及出现在列表上下文中的所有参数扩展。

此外,数组索引(除了"$@"Bourne 数组)在bashlike in ksh(但与大多数其他 shell 不同)中,从 0 开始,而不是 1。

因此,对于您的方法,语法应该是:

#! /usr/bin/bash -
PROGNAME=$0
die() {
  (( $# == 0 )) || printf >&2 '%s: ERROR: %s\n' "$PROGNAME" "$1"
  exit 1
}

IFS= read -rp "Enter the number of names of students: " classcount || die

# validate to avoid command injection vulnerability
shopt -s extglob # only needed in older versions of bash
[[ $classcount = @(0|[123456789]*([0123456789])) ]] ||
  die "Not a valid decimal integer number: $classcount"

for (( i = 1; i <= classcount; i++ )); do
  IFS= read -rp "Student $i: " 'names[i-1]' ||
    die "$(( classcount - i + 1 )) students missing"
done

for (( i=1; i <= classcount; i++)); do
  printf 'Student %s: %s\n' "$i" "${names[i-1]}"
done
Run Code Online (Sandbox Code Playgroud)

$name[$i]在 (t)csh(70 年代末首次引入数组的 shell)中是有效的,尽管您需要$name[$i]:q确保空格或通配符在它们中或在 zsh 中不被特殊处理,但不是在bash其中复制的ksh' s 阵列设计。

在这方面,ksh 努力与 Bourne shell 向后兼容,因此echo $name[$i]会像在 Bourne shell 中一样输出与<contents-of-$name>[<contents-of-$i>]模式匹配的文件列表($name并且$i也会受到拆分)。

在 ksh/bash 中,您需要${name[i]}语法(${name[$i]}或${name[${i}]}也可以使用),并且对于每个参数扩展,请确保将其引用 ( "${name[i]}") 以防止 split+glob。

在任何情况下,echo都不能用于输出任意数据。