如何在 sh -c 内运行循环

如何在 sh -c 内运行循环

我无法理解使用时需要转义的内容sh -c

假设我想运行 for 循环for i in {1..4}; do echo $i; done。就其本身而言,这工作得很好。如果我将它传递给eval,我需要转义$: eval "for i in {1..4}; do echo \$i; done",但我不能让它工作sh -c "[...]"

$ sh -c "for i in {1..4}; do echo $i; done"
4

$ sh -c "for i in {1..4}; do echo \$i; done"
{1..4}

$ sh -c "for i in \{1..4\}; do echo \$i; done"
{1..4}

$ sh -c "for i in \{1..4\}\; do echo \$i\; done"
sh: 1: Syntax error: end of file unexpected

我在哪里可以找到有关此的更多信息?

答案1

-c通常的做法是在单引号内定义脚本(在 后面)。您需要使用的另一部分是一个外壳,其中{1..4}构造有效:

$ bash -c 'for i in {1..4}; do echo $i; done'  # also work with ksh and zsh

让它与 dash (你的sh)一起工作的一种替代方法是在你正在交互使用的 shell 上进行扩展(我假设你使用 bash 或 zsh 作为你的交互式 shell):

$ dash -c 'for i do echo $i; done' mysh {1..4}
1
2
3
4

答案2

{1..4}csh是一个 zsh 运算符,从的大括号扩展运算符扩展而来,{x,y}现在其他一些 shell 支持,但它不是 POSIX sh 运算符(直到最近,POSIX 实际上甚至必需的 echo {1..4}来输出{1..4})。

即使在 zsh 或现在支持的其他 shell 中{x..y},这也不是执行递增整数变量的循环的最佳方法,因为您最终会分配所有值的列表(此处仅分配 4 个值,但扩展性不佳)。for i in $(seq 4)seq存在不是标准命令)除了依赖于 的当前值之外,也存在同样的问题$IFS

在 ksh93、bash、zsh 中,使用:

for (( i = 1; i <= 4; i++ )); do
  printf '%s\n' "$i"
done

一般认为比较好。它还允许负值,并且可以更好地控制索引的增量方式。

{x..y}方法的优点是允许在多个范围内循环,或在字母上循环,或使用填充(尽管根据 shell 及其版本有所不同):

for i in {1..5} {9..12} x{0..3} {f..p} {001..0010}; do
  ...
done

在 中zsh,另请参阅:

i=; repeat 4 printf '%s\n' $((++i))

在 POSIX 中sh,你会这样做:

i=1; while [ "$i" -le 4 ]; do
  printf '%s\n' "$i"
  i=$(( i + 1 ))
done

或者:

sh -c '
  i=1; while [ "$i" -le 4 ]; do
    printf "%s\n" "$i"
    i=$(( i + 1 ))
  done'

如果您需要新的sh调用,请从另一个 Bourne/rc/fish 之类的 shell 中运行该循环。

当然,在这里,你也可以这样做:

for i in 1 2 3 4; do
  printf '%s\n' "$i"
done

相关内容