我需要将输出从ps
,这是间隔分开的。
#!/bin/bash
A=$(ps -r -e -o pcpu=,comm= | head -1)
B=${A[0]}
C=${A[1]}
printf '%3s %s\n' $B $(basename $C)
Run Code Online (Sandbox Code Playgroud)
输出应该是:
42 bar
Run Code Online (Sandbox Code Playgroud)
相反,我得到:
usage: basename ...
Run Code Online (Sandbox Code Playgroud)
为什么这不起作用,最重要的是,我如何使它起作用?
要在空格字符上拆分字符串,可以使用 split+glob 运算符。这是在命令替换或参数扩展时调用的,但显然不是在存储到最多只能存储一个值的标量变量中。
var=$(...)
Run Code Online (Sandbox Code Playgroud)
是标量变量赋值。所以会将整个输出分配给$var
,与${var[0]}
. 对于数组变量赋值,它是:
var=($(...))
Run Code Online (Sandbox Code Playgroud)
现在,在调用它之前,一如既往,您需要对其进行调整:
set -o noglob # disable the glob part which you don't want here
IFS=' ' # split on space only
var=($(some command)) # invoke it
Run Code Online (Sandbox Code Playgroud)
请注意,它在空格序列上拆分,并且忽略前导和尾随空格。
然后,你不想调用它的扩张$B
,也不$C
也不$(basename...)
所以你需要引用这些:
printf '%3s %s\n' "$B" "$(basename -- "$C")"
Run Code Online (Sandbox Code Playgroud)
也不要忘记--
标记选项的结束。
因为您忘记了周围的引号$C
($C
在您的情况下为空,因为${A[1]}
从未分配任何值),basename
所以没有传递任何参数,而不是传递该空参数并抱怨它。
其他人已经注意到您的代码中的错误是什么,并正确建议对于您的初始占位符数据,数组将是更好的数据结构选择,以及如何确保正确拆分字符串等。
现在我们知道您正在解析的实际命令是什么,我们可以通过改进建议稍微更有创意。
以下脚本将获取命令的每一行输出ps
并将其作为两个空格分隔的位读取。循环体以不同方式输出读取位:
#!/bin/bash
ps -r -e -o pcpu=,comm= |
while IFS=' ' read -r pcpu comm; do
printf 'pcpu=%s,\tcomm=%s,\tbasename of comm=%s\n' \
"$pcpu" "$comm" "${comm##*/}"
done
Run Code Online (Sandbox Code Playgroud)
在这里,comm
将保存输出中第一个空格序列之后的所有内容ps
(第一列之前的初始空格将被修剪掉)。
head -n 1
如果您愿意,您显然可以将您的作为初始管道的一部分插入。
请注意,在某些 shell 中,包括bash
,循环在子 shell 中运行,因此在管道完成后创建的任何变量都将不可用。有两种解决方案bash
:
lastpipe
与脚本shell选项shopt -s lastpipe
,或使用进程替换将数据读入循环:
while IFS=' ' read ...
# ...
done < <( ps ... )
Run Code Online (Sandbox Code Playgroud)示例运行:
$ bash script.sh
pcpu=0.0, comm=tmux, basename of comm=tmux
pcpu=0.0, comm=sh, basename of comm=sh
pcpu=0.0, comm=sh, basename of comm=sh
pcpu=0.0, comm=bash, basename of comm=bash
pcpu=0.0, comm=bash, basename of comm=bash
pcpu=0.0, comm=bash, basename of comm=bash
pcpu=0.0, comm=ps, basename of comm=ps
pcpu=0.0, comm=sh, basename of comm=sh
Run Code Online (Sandbox Code Playgroud)