sed를 사용하여 여러 공백을 하나로 제거하는 방법은 무엇입니까?


69

sedAIX에서 내가 생각하는 것을하지 않습니다. IOSTAT 출력에서 ​​여러 공백을 단일 공백으로 바꾸려고합니다.

# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty:      tin         tout    avg-cpu: % user % sys % idle % iowait
          0.2         31.8                9.7   4.9   82.9      2.5

Disks:        % tm_act     Kbps      tps    Kb_read   Kb_wrtn
hdisk9           0.2      54.2       1.1   1073456960  436765896
hdisk7           0.2      54.1       1.1   1070600212  435678280
hdisk8           0.0       0.0       0.0          0         0
hdisk6           0.0       0.0       0.0          0         0
hdisk1           0.1       6.3       0.5   63344916  112429672
hdisk0           0.1       5.0       0.2   40967838  98574444
cd0              0.0       0.0       0.0          0         0
hdiskpower1      0.2     108.3       2.3   2144057172  872444176

# iostat | grep hdisk1
hdisk1           0.1       6.3       0.5   63345700  112431123

#iostat|grep "hdisk1"|sed -e"s/[ ]*/ /g"
 h d i s k 1 0 . 1 6 . 3 0 . 5 6 3 3 4 5 8 8 0 1 1 2 4 3 2 3 5 4

sed는 전체 그룹 (/ g)에 대해 여러 공백 (/ [] * /)을 단일 공백 ​​(/ /)으로 검색하고 교체해야하지만 ... 각 문자 사이의 간격을 유지해야합니다.

내가 무엇을 잘못하고 있지? 나는 그것이 단순한 무언가가되어야한다는 것을 알고있다 ... AIX 5300-06

편집 : 10 개 이상의 하드 드라이브가있는 다른 컴퓨터가 있습니다. 이것을 모니터링 목적으로 다른 프로그램의 매개 변수로 사용하고 있습니다.

내가 부딪친 문제는 2 단계에서 $ 1 등을 사용하고 있고 인쇄 명령에 오류가있어서 "awk '{print $ 5}'가 작동하지 않는다는 것입니다. 나는 grep / sed / cut 버전을 찾고있었습니다 작동하는 것 같습니다 :

iostat | grep "hdisk1 " | sed -e's/  */ /g' | cut -d" " -f 5

그들이 "단 하나"를 의미한다고 생각했을 때 []는 "0 이상"이었습니다. 브래킷을 제거하면 작동합니다. 세 가지 좋은 답변은 실제로 "답변"을 선택하기 어렵게 만듭니다.

답변:


52

사용 grep이 중복 sed되어 동일하게 수행 할 수 있습니다. 문제는 *해당 일치도 0 공백을 사용하는 \+것입니다. 대신 사용해야 합니다.

iostat | sed -n '/hdisk1/s/ \+/ /gp'

귀하의 경우 sed지원하지 않는 \+metachar를, 다음 할

iostat | sed -n '/hdisk1/s/  */ /gp'

AIX는 +를 지원하지 않지만, []를 제거하면 트릭을 수행 한 것으로 보입니다.
WernerCD

나는 sed -n 버전을 사용해 보았습니다 ... 어떻게하면 10 개 이상의 드라이브가있는 다른 컴퓨터가있어서 1, 10, 11 등을 시작합니다 ... 공백을 추가하려고 시도했습니다 / hdisk1 / "인식되지 않은 기능" 작동하는 것 같습니다 >> iostat | grep "hdisk1"| sed -e 's / * / / g '
WernerCD

67

/[ ]*/0 개 이상의 공백 과 일치 하므로 문자 사이의 빈 문자열이 일치합니다.

"하나 이상의 공백"과 일치 시키려면 다음 중 하나를 사용하십시오.

... | sed 's/  */ /g'
... | sed 's/ \{1,\}/ /g'
... | tr -s ' '

Ahh ... []는 "선택적"입니다. 그것은 그것을 설명합니다.
WernerCD

5
@WernerCD, 아니오 *"선택적". [ ]단지 하나의 문자 (공백)로 문자 목록을 만듭니다. 그것은 한정사이다 *"제로 또는 이전 것보다"를 의미
글렌 잭맨

Ahh ... 더 정확하게 말하면 단일 공간 / * /에서 이중 공간으로 변경하는 것이 그 당시의 일입니다. 알았어
WernerCD

이중 공간 만 검색하는 패턴을 검색하려고했지만 멋지게 작동했습니다.
minhas23

6
가장 간단한 tr -s ' '솔루션 +1
Andrejs

12

교환 *원을로 변경하십시오 +. 공백이 아닌 모든 것이 ... 음 ... 제로 인스턴스이기 때문에 모든 문자와 일치하는 이전 문자 중 0 이상을 일치시킵니다. 하나 이상 일치해야합니다. 실제로 두 개 이상 일치하는 것이 좋습니다

한 문자를 일치시키는 데 대괄호 문자 클래스도 필요하지 않습니다. 당신은 단지 사용할 수 있습니다 :

s/  \+/ /g

... 탭이나 다른 종류의 공백과 일치시키지 않으려면 문자 클래스를 사용하는 것이 좋습니다.


AIX는 +를 지원하지 않는 것 같습니다.
WernerCD

1
@WernerCD : 그런 다음 시도하십시오 s/ */ /g(공백이 3 개 있으면 주석 형식이 축소됩니다). 별표 연산자는 이전 문자를 선택 사항으로 만들므로, 둘 이상의 문자를 일치 시키려면 처음 두 문자 (두 공백)를 일치시킨 다음 세 번째 공백과 별을 추가하여 세 번째 공백과 다음 공백을 선택적으로 만들어야합니다.
Caleb

3
@userunknown : 사실 나는 두 가지를 전혀 섞지 않고 있습니다. 다른 모든 사람들은 :) 단일 공간을 단일 공간으로 교체하는 것은 의미가 없으며, 적어도 두 개의 순차적 공간이있는 경기에서만이 작업을 수행하면됩니다. 두 개의 공백과 플러스 또는 세 개의 공백과 별이 정확히 필요한 것입니다.
Caleb

@userunknown : 처리 시간을 조금만 낭비하고 매치 카운터와 같은 것을 버리는 것은 큰 문제가 아닙니다.
Caleb

8

다음과 같은 순서로 마지막 항목을 항상 일치시킬 수 있습니다.

s/\(sequence\)*/\1/

그래서 당신은 올바른 길을 가고 있지만 시퀀스를 공백으로 바꾸는 것이 아니라 마지막 공백 인 단일 공백으로 바꾸십시오. 이렇게하면 일련의 공백 일치하면 시퀀스가 ​​단일 공백으로 축소되지만 null 문자열이 일치하면 null 문자열이 자체로 바뀌고 해가 없으며 파울이 없습니다. 예를 들어,

sed 's/\( \)*/\1/g' <<\IN                                    
# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty:      tin         tout    avg-cpu: % user % sys % idle % iowait
          0.2         31.8                9.7   4.9   82.9      2.5

Disks:        % tm_act     Kbps      tps    Kb_read   Kb_wrtn
hdisk9           0.2      54.2       1.1   1073456960  436765896
hdisk7           0.2      54.1       1.1   1070600212  435678280
hdisk8           0.0       0.0       0.0          0         0
hdisk6           0.0       0.0       0.0          0         0
hdisk1           0.1       6.3       0.5   63344916  112429672
hdisk0           0.1       5.0       0.2   40967838  98574444
cd0              0.0       0.0       0.0          0         0
hdiskpower1      0.2     108.3       2.3   2144057172  872444176

# iostat | grep hdisk1
hdisk1           0.1       6.3       0.5   63345700  112431123

IN

산출

# iostat
System configuration: lcpu=4 drives=8 paths=2 vdisks=0

tty: tin tout avg-cpu: % user % sys % idle % iowait
 0.2 31.8 9.7 4.9 82.9 2.5

Disks: % tm_act Kbps tps Kb_read Kb_wrtn
hdisk9 0.2 54.2 1.1 1073456960 436765896
hdisk7 0.2 54.1 1.1 1070600212 435678280
hdisk8 0.0 0.0 0.0 0 0
hdisk6 0.0 0.0 0.0 0 0
hdisk1 0.1 6.3 0.5 63344916 112429672
hdisk0 0.1 5.0 0.2 40967838 98574444
cd0 0.0 0.0 0.0 0 0
hdiskpower1 0.2 108.3 2.3 2144057172 872444176

# iostat | grep hdisk1
hdisk1 0.1 6.3 0.5 63345700 112431123

그러나이 상황에서 정규 표현식을 완전히 피하고 대신 수행하는 것이 훨씬 낫습니다.

tr -s \  <infile

4
실제 답변의 단순성을 위해 +1iostat | tr -s \
Wildcard

'tr -s \'는 'tr -s ""'와 동일합니다. "\"로 이스케이프 처리하여 문자열에서 공백을 인수로 전달할 수 있음을 알았습니다. 쉘 스크립트에서도 사용할 수 있음을 알았습니다. 멋진 응용 프로그램.
randominstanceOfLivingThing

5

시도하는 작업을 수행 할 수도 있습니다.

iostat | grep "hdisk1 " | sed -e's/  */ /g' | cut -d" " -f 5

으로, ~에 의하여

iostat | while read disk tma kbps tps re wr; do [ "$disk" = "hdisk1" ] && echo "$re"; done

나중에 다른 필드에 액세스하거나 무언가를 계산하려고 할 때 특히 유용 할 수 있습니다.

iostat | while read disk tma kbps tps re wr; do [ "$disk" = "hdisk1" ] && echo "$(( re/1024 )) Mb"; done

아주 좋아요 첫 번째 버전이 작동합니다. 내 AIX 상자는 두 번째 상자를 좋아하지 않는 것 같습니다. 세 개의 상자 모두 출력 : "$ [re / 1024] Mb". 내가 사용하는 모니터링 도구에는 보고서 변환이 포함되어있어 "필요한"것은 아니지만 마음에 듭니다.
WernerCD

@enzotib를 수정 해 주셔서 감사합니다 while.
rozcietrzewiacz

@WernerCD 아, 이것은 $[ .. ]아마도 최신 버전의 bash (아마도 zsh)에서 사용할 수 있습니다. $(( .. ))대신 더 휴대하기 쉬운 답변을 업데이트했습니다 .
rozcietrzewiacz

그 트릭을했다. 나는 그것을 찾아야 할 것이다. 멋진.
WernerCD

0

다음 스크립트를 사용하여 여러 공백을 단일 공백, TAB 또는 다른 문자열로 변환 할 수 있습니다.

$ ls | compress_spaces.sh       # converts multiple spaces to one
$ ls | compress_spaces.sh TAB   # converts multiple spaces to a single tab character
$ ls | compress_spaces.sh TEST  # converts multiple spaces to the phrase TEST
$ compress_spaces.sh help       # show the help for this command

compress_spaces.sh

function show_help()
{
  IT=$(CAT <<EOF

  usage: {REPLACE_WITH}

  NOTE: If you pass in TAB, then multiple spaces are replaced with a TAB character

  no args -> multiple spaces replaced with a single space
  TAB     -> multiple spaces replaced with a single tab character
  TEST    -> multiple spaces replaced with the phrase "TEST"

  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show help if we're not getting data from stdin
if [ -t 0 ]; then
  show_help
fi

REPLACE_WITH=${1:-' '}

if [ "$REPLACE_WITH" == "tab" ]
then
  REPLACE_WITH=$'\t'
fi
if [ "$REPLACE_WITH" == "TAB" ]
then
  REPLACE_WITH=$'\t'
fi

sed "s/ \{1,\}/$REPLACE_WITH/gp"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.