【问题标题】:shell - put variable in ALPHABETICAL range of cycleshell - 将变量放在循环的 ALPHABETICAL 范围内
【发布时间】:2014-09-06 16:58:12
【问题描述】:
有没有办法把变量放在循环的字母范围内?
这不起作用。
read -p "Where I should start?" start #there will be entered one small letter
for aaa in {$start..z}; do #how put variable $start in range?
...
done
感谢回复。
【问题讨论】:
标签:
bash
variables
range
alphabetical
【解决方案1】:
使用eval扩展变量:
$ s=t
$ eval echo {$s..z}
t u v w x y z
你的例子就变成了:
read -p "Where I should start?" start #there will be entered one small letter
for aaa in $(eval echo {$start..z}); do
echo $aaa
done
由于您有eval 的用户输入,您可能需要先检查 start 的值是否为单个小写字符:
read -p "Where I should start?" start #there will be entered one small letter
if [[ $start =~ ^[a-y]$ ]]; then
for aaa in $(eval echo {$start..z}); do
echo $aaa
done
else
echo "Need to use a letter 'a-y'"
fi
您可以阅读有关 Bash 大括号扩展的更多信息 here
【解决方案2】:
很遗憾,您不能将变量放在 bash 中的 {start..end} 范围内。
这就是你想要的:
until [[ $s == "_" ]]; do echo $s && s=$(tr "a-z" "b-z_" <<<$s); done
它使用tr 将每个字符转换为下一个字符。 “_”是“z”后面的字符。
例如:
$ s=t
$ until [[ $s == "_" ]]; do echo $s && s=$(tr "a-z" "b-z_" <<<$s); done
t
u
v
w
x
y
z
如果你不介意使用 Perl,你可以使用这个:
perl -le 'print for shift .. "z"' $s
它使用.. 在命令行的第一个参数和“z”之间创建一个列表。
在 bash 中更深奥的方法是:
for ((i=$(LC_CTYPE=C printf '%d' "'$s"); i<=122; ++i)); do
printf "\\$(printf '%03o' $i)\n"
done
for 循环从变量 $s 的 ASCII 字符编号变为“z”,即 ASCII 字符 122。内部的格式说明符 printf 将字符编号转换为八进制,并用零填充最多三个字符。外部printf 然后将其解释为转义序列并打印字符。 感谢 Greg's wiki 用于将 ASCII 字符转换为其值的代码。
当然,您可以只使用eval 来扩展变量,这样做的好处是所需的代码要短得多。但是,执行已读入脚本的任意字符串可能存在安全漏洞。
【解决方案3】:
x=t
for I in $(sed -nr "s/.*($x.*)/\1/;s/ /\n/g;p" <(echo {a..z}))
do
# do something with $I
done
输出:
吨
你
v
w
X
是的
z
【解决方案4】:
我会避免使用eval。
for aaa in {a..z}; do
[[ $aaa < $start ]] && continue
...
done
比较$aaa 和$start 的开销应该可以忽略不计,尤其是与启动单独进程来计算范围的成本相比。