文字列を空白文字に分割する(デフォルト名に奇妙な問題がある)

文字列を空白文字に分割する(デフォルト名に奇妙な問題がある)

出力を分離する必要がありますが、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

文字列を空白文字に分割するには、分割+グローブ演算子を使用します。これはコマンド置換またはパラメータ拡張時に呼び出されますが、明らかにスカラー最大1つの値を格納できる変数。

 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

分かれています。注文スペースと先行および末尾のスペースは無視されます。

その後、$BNorの拡張から呼び出したくないので、引用する必要があります。$C$(basename...)

 printf '%3s  %s\n' "$B" "$(basename -- "$C")"

--また、オプションの終わりを表示することを忘れないでください。

引用符$C$Cあなたの場合は${A[1]}値が割り当てられていないため空です)を忘れたため、空の引数を渡し、basenameそれについて文句を言う代わりに引数は渡されません。

答え2

他の人たちは、コードのエラーが何であるかを知り、初期プレースホルダデータの配列がより良いデータ構造の選択になることを正しく提案し、文字列が正しく分割されているかどうかを確認する方法などもありました。

これで、構文解析中の実際のコマンドが何であるかがわかりました。

次のスクリプトは、コマンド出力の各行をpsスペースで区切られた2ビットとして読み込みます。ループの本文は読み出しビットをさまざまな方法で出力します。

#!/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

一部のシェル(含む)では、bashループがサブシェルで実行されるため、その中に生成されたすべての変数はパイプラインが完了した後に使用できません。これには2つの解決策がありますbash

  1. lastpipeスクリプトでシェルオプションを有効または有効にします。shopt -s lastpipe
  2. 手続き型置換を介してループにデータを読み込みます。

    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]}'

関連情報