我不乐意使用eval,但我尝试的其他所有内容都因{a..b}
语法限制而失败.这就是我所拥有的,是的,我知道我可以将这两个循环结合起来,但eval已经足够丑陋了.
cores="" suffixes="" np=$(nproc --all) eval 'for i in {1..'$np'} ; do cores="$cores $i"; done' for i in $cores ; do suffixes="$suffixes "$(printf %02i $i) done
Charles Duff.. 7
首先,一个积极的现代解决方案:
#!/bin/bash # ^^^^- "printf -v" and C-style for loops both require bash, not /bin/sh np=$(nproc --all) cores=( ) for ((i=0; i这会生成一个索引数组:其键是核心数,其值是后缀字符串.因此,您可以迭代
"${!cores[@]}"
以获取核心数列表; 在"${cores[@]}"
获得后缀字符串列表,或使用"${cores[$i]}"
查找后缀为核心$i
.
接下来,一个更接近原始代码的解决方案,为现代bash构建:
#!/bin/bash # ^^^^- "printf -v" and C-style for loops both require bash, not /bin/sh np=$(nproc --all) cores=""; suffixes="" for ((i=0; i您还可以仅在数组中构建核心数字,并在一个步骤中计算后缀数字:
# read cores from string into an array to allow safe evaluation even with unknown IFS IFS=' ' read -r -a cores_arr <<<"$cores" # ...and expand the full array, repeating the format string for every element printf -v suffixes '%02i ' "${cores_arr[@]}"值得注意的是:
迭代扩展数组,即.
for i in $cores
,通常是不好的做法 - 如果你的价值保证只是数字,它可以是安全的,但要注意副作用:
字符串中的Glob表达式被扩展:如果你以某种方式
*
在数据中有一个,你会发现自己在当前目录中迭代文件.字符串拆分不允许对数组所执行的元素边界进行细粒度控制.您必须
array=( "item one" "item two" )
存储两个项目,其名称中包含空格; 如果你尝试设置string=' "item one" "item two" '
,你会得到"item
一个单词,one"
作为第二个单词,等等.
因此,迭代数组元素 - 即使这意味着从字符串读取到数组 - 是非常优选的.
循环使用任意数量的项目最好使用C风格的
for
循环.在上面,除了以外没有外部命令
nproc
.这意味着我们不依赖于非POSIX工具seq
.使用
printf -v suffix
将printf
直接执行的字符串格式化操作的结果写入名为的变量suffix
.(旁白:ksh93没有printf -v
,但识别内部使用printf$()
并避免子shell惩罚).请参阅bash-hackers页面printf
.因此:除了运行所述外部命令并捕获其输出所需的子设备之外,没有其他子设备.(每个子
fork()
shell在使用mkfifo()
生成FIFO以捕获其输出之后需要关闭shell的另一个副本;读取该输出;wait()
输入子shell以退出等;因此,它们最好保持在紧密循环之外).
相比之下,如果你需要与POSIX sh的兼容性,那么我们仍然有
$(( ))
但没有(( ))
(+=
除了数学上下文之外没有任何操作,根本没有C风格的for
循环).这让我们:#!/bin/sh build_suffix() { np=$1; i=0 while [ "$i" -lt "$np" ]; do printf '%02i ' "$i" i=$((i+1)) done } suffixes=$(build_suffix "$(nproc --all)")...通过将整个循环放在单个子壳内,无论我们循环多少次,它都能给出一个恰好两个子壳的答案.
1> Charles Duff..:首先,一个积极的现代解决方案:
#!/bin/bash # ^^^^- "printf -v" and C-style for loops both require bash, not /bin/sh np=$(nproc --all) cores=( ) for ((i=0; i这会生成一个索引数组:其键是核心数,其值是后缀字符串.因此,您可以迭代
"${!cores[@]}"
以获取核心数列表; 在"${cores[@]}"
获得后缀字符串列表,或使用"${cores[$i]}"
查找后缀为核心$i
.
接下来,一个更接近原始代码的解决方案,为现代bash构建:
#!/bin/bash # ^^^^- "printf -v" and C-style for loops both require bash, not /bin/sh np=$(nproc --all) cores=""; suffixes="" for ((i=0; i您还可以仅在数组中构建核心数字,并在一个步骤中计算后缀数字:
# read cores from string into an array to allow safe evaluation even with unknown IFS IFS=' ' read -r -a cores_arr <<<"$cores" # ...and expand the full array, repeating the format string for every element printf -v suffixes '%02i ' "${cores_arr[@]}"值得注意的是:
迭代扩展数组,即.
for i in $cores
,通常是不好的做法 - 如果你的价值保证只是数字,它可以是安全的,但要注意副作用:
字符串中的Glob表达式被扩展:如果你以某种方式
*
在数据中有一个,你会发现自己在当前目录中迭代文件.字符串拆分不允许对数组所执行的元素边界进行细粒度控制.您必须
array=( "item one" "item two" )
存储两个项目,其名称中包含空格; 如果你尝试设置string=' "item one" "item two" '
,你会得到"item
一个单词,one"
作为第二个单词,等等.
因此,迭代数组元素 - 即使这意味着从字符串读取到数组 - 是非常优选的.
循环使用任意数量的项目最好使用C风格的
for
循环.在上面,除了以外没有外部命令
nproc
.这意味着我们不依赖于非POSIX工具seq
.使用
printf -v suffix
将printf
直接执行的字符串格式化操作的结果写入名为的变量suffix
.(旁白:ksh93没有printf -v
,但识别内部使用printf$()
并避免子shell惩罚).请参阅bash-hackers页面printf
.因此:除了运行所述外部命令并捕获其输出所需的子设备之外,没有其他子设备.(每个子
fork()
shell在使用mkfifo()
生成FIFO以捕获其输出之后需要关闭shell的另一个副本;读取该输出;wait()
输入子shell以退出等;因此,它们最好保持在紧密循环之外).
相比之下,如果你需要与POSIX sh的兼容性,那么我们仍然有
$(( ))
但没有(( ))
(+=
除了数学上下文之外没有任何操作,根本没有C风格的for
循环).这让我们:#!/bin/sh build_suffix() { np=$1; i=0 while [ "$i" -lt "$np" ]; do printf '%02i ' "$i" i=$((i+1)) done } suffixes=$(build_suffix "$(nproc --all)")...通过将整个循环放在单个子壳内,无论我们循环多少次,它都能给出一个恰好两个子壳的答案.