출력을 분리해야 하는데 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
문자열을 공백 문자로 분할하려면 분할+글로브 연산자를 사용하십시오. 이는 명령 대체 또는 매개변수 확장 시 호출되지만 분명히스칼라최대 하나의 값을 저장할 수 있는 변수입니다.
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
.
일부 셸(포함)에서는 bash
루프가 하위 셸에서 실행되므로 그 안에 생성된 모든 변수는 파이프라인이 완료된 후에 사용할 수 없습니다. 이에 대한 두 가지 해결책이 있습니다 bash
.
lastpipe
스크립트에서 셸 옵션을 사용하거나 활성화합니다.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]}'