按空格字符拆分字符串(basename 的奇怪问题)

for*_*rin 4 bash

我需要将输出从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)

为什么这不起作用,最重要的是,我如何使它起作用?

Sté*_*las 6

要在空格字符上拆分字符串,可以使用 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所以没有传递任何参数,而不是传递该空参数并抱怨它。


Kus*_*nda 5

其他人已经注意到您的代码中的错误是什么,并正确建议对于您的初始占位符数据,数组将是更好的数据结构选择,以及如何确保正确拆分字符串等。

现在我们知道您正在解析的实际命令是什么,我们可以通过改进建议稍微更有创意。

以下脚本将获取命令的每一行输出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

  1. 启用lastpipe与脚本shell选项shopt -s lastpipe,或
  2. 使用进程替换将数据读入循环:

    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)

  • @forthrin 每当我看到有人将命令的输出存储到变量中时,我都想知道实际的命令是什么。可能有比将数据存储在变量中更好的处理数据的方法,特别是如果命令输出的不仅仅是一个不需要进一步处理的简单字符串。 (2认同)