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