如何用 shell 迭代 Linux cpuset?
How can a Linux cpuset be iterated over with shell?
Linux 的 sys 文件系统表示 CPU 组 ID,其语法为:
0,2,8
:包含 0、2 和 8 的 CPU 集合。
4-6
:一组 CPU,包含 4、5 和 6。
- 两种语法可以混合搭配,例如:
0,2,4-6,8
例如,运行 cat /sys/devices/system/cpu/online
在我的机器上打印 0-3
这意味着 CPUs 0、1、2 和 3 在线。
问题是上述语法很难在 shell 脚本中使用 for 循环迭代。如何将上述语法转换为更常规的语法,例如 0 2 4 5 6 8
?
eval echo $(cat /sys/devices/system/cpu/online | sed 's/\([[:digit:]]\+\)-\([[:digit:]]\+\)/$(seq )/g' | tr , ' ')
解释:
cat /sys/devices/system/cpu/online
从 sysfs 读取文件。这可以更改为任何其他文件,例如 offline
.
- 输出通过替换管道传输
s/\([[:digit:]]\+\)-\([[:digit:]]\+\)/$(seq )/g
。这匹配 4-6
之类的内容并将其替换为 $(seq 4 6)
.
tr , ' '
将所有逗号替换为空格。
- 此时输入
0,2,4-6,8
被转化为0 2 $(seq 4 6) 8
。最后一步就是eval
这个序列得到0 2 4 5 6 8
.
- 示例
echo
的输出。或者,它可以写入变量或在 for 循环中使用。
尝试:
$ echo 0,2,4-6,8 | awk '/-/{for (i=; i<=; i++)printf "%s%s",i,ORS;next} 1' ORS=' ' RS=, FS=-
0 2 4 5 6 8
这可以在循环中使用,如下所示:
for n in $(echo 0,2,4-6,8 | awk '/-/{for (i=; i<=; i++)printf "%s%s",i,ORS;next} 1' RS=, FS=-)
do
echo cpu="$n"
done
产生输出:
cpu=0
cpu=2
cpu=4
cpu=5
cpu=6
cpu=8
或喜欢:
printf "%s" 0,2,4-6,8 | awk '/-/{for (i=; i<=; i++)printf "%s%s",i,ORS;next} 1' RS=, FS=- | while read n
do
echo cpu="$n"
done
这也会产生:
cpu=0
cpu=2
cpu=4
cpu=5
cpu=6
cpu=8
工作原理
awk 命令的工作原理如下:
RS=,
这告诉 awk 使用 ,
作为记录分隔符。
例如,如果输入是 0,2,4-6,8
,则 awk 将看到四个记录:0
和 2
以及 4-6
和 8
。
FS=-
这告诉 awk 使用 -
作为字段分隔符。
以这种方式设置 FS
,例如,如果输入记录由 2-4
组成,则 awk 会将 2
视为第一个字段,而 4
作为第二个字段。
/-/{for (i=; i<=; i++)printf "%s%s",i,ORS;next}
对于包含 -
的任何记录,我们打印出从第一个字段的值 </code> 开始到第二个字段的值 <code>
结束的每个数字].每个这样的数字后跟输出记录分隔符 ORS
。默认情况下,ORS
是换行符。对于上面的一些示例,我们将 ORS
设置为空白。
打印完这些数字后,我们跳过其余的命令并跳转到 next
记录。
1
如果我们到达这里,则记录不包含 -
,我们按原样打印出来。 1
是 awk 用于打印行的 shorthand。
一个 Perl:
echo "0,2,4-6,8" | perl -lpe 's/(\d+)-(\d+)/{..}/g; $_="echo {$_}"' | bash
只需将原始字符串转换为echo {0,2,{4..6},8}
,然后让bash 'brace expansion'进行插值即可。
Linux 的 sys 文件系统表示 CPU 组 ID,其语法为:
0,2,8
:包含 0、2 和 8 的 CPU 集合。4-6
:一组 CPU,包含 4、5 和 6。- 两种语法可以混合搭配,例如:
0,2,4-6,8
例如,运行 cat /sys/devices/system/cpu/online
在我的机器上打印 0-3
这意味着 CPUs 0、1、2 和 3 在线。
问题是上述语法很难在 shell 脚本中使用 for 循环迭代。如何将上述语法转换为更常规的语法,例如 0 2 4 5 6 8
?
eval echo $(cat /sys/devices/system/cpu/online | sed 's/\([[:digit:]]\+\)-\([[:digit:]]\+\)/$(seq )/g' | tr , ' ')
解释:
cat /sys/devices/system/cpu/online
从 sysfs 读取文件。这可以更改为任何其他文件,例如offline
.- 输出通过替换管道传输
s/\([[:digit:]]\+\)-\([[:digit:]]\+\)/$(seq )/g
。这匹配4-6
之类的内容并将其替换为$(seq 4 6)
. tr , ' '
将所有逗号替换为空格。- 此时输入
0,2,4-6,8
被转化为0 2 $(seq 4 6) 8
。最后一步就是eval
这个序列得到0 2 4 5 6 8
. - 示例
echo
的输出。或者,它可以写入变量或在 for 循环中使用。
尝试:
$ echo 0,2,4-6,8 | awk '/-/{for (i=; i<=; i++)printf "%s%s",i,ORS;next} 1' ORS=' ' RS=, FS=-
0 2 4 5 6 8
这可以在循环中使用,如下所示:
for n in $(echo 0,2,4-6,8 | awk '/-/{for (i=; i<=; i++)printf "%s%s",i,ORS;next} 1' RS=, FS=-)
do
echo cpu="$n"
done
产生输出:
cpu=0
cpu=2
cpu=4
cpu=5
cpu=6
cpu=8
或喜欢:
printf "%s" 0,2,4-6,8 | awk '/-/{for (i=; i<=; i++)printf "%s%s",i,ORS;next} 1' RS=, FS=- | while read n
do
echo cpu="$n"
done
这也会产生:
cpu=0
cpu=2
cpu=4
cpu=5
cpu=6
cpu=8
工作原理
awk 命令的工作原理如下:
RS=,
这告诉 awk 使用
,
作为记录分隔符。例如,如果输入是
0,2,4-6,8
,则 awk 将看到四个记录:0
和2
以及4-6
和8
。FS=-
这告诉 awk 使用
-
作为字段分隔符。以这种方式设置
FS
,例如,如果输入记录由2-4
组成,则 awk 会将2
视为第一个字段,而4
作为第二个字段。/-/{for (i=; i<=; i++)printf "%s%s",i,ORS;next}
对于包含
-
的任何记录,我们打印出从第一个字段的值</code> 开始到第二个字段的值 <code>
结束的每个数字].每个这样的数字后跟输出记录分隔符ORS
。默认情况下,ORS
是换行符。对于上面的一些示例,我们将ORS
设置为空白。打印完这些数字后,我们跳过其余的命令并跳转到
next
记录。1
如果我们到达这里,则记录不包含
-
,我们按原样打印出来。1
是 awk 用于打印行的 shorthand。
一个 Perl:
echo "0,2,4-6,8" | perl -lpe 's/(\d+)-(\d+)/{..}/g; $_="echo {$_}"' | bash
只需将原始字符串转换为echo {0,2,{4..6},8}
,然后让bash 'brace expansion'进行插值即可。