각 줄 앞에 문자열을 추가하는 명령?


36

이와 같은 것을 찾고 계십니까? 어떤 아이디어?

cmd | prepend "[ERRORS] "

[ERROR] line1 text
[ERROR] line2 text
[ERROR] line3 text
... etc

bash 함수 / 스크립트의 모든 명령에 대해 이것을 설정하는 방법이 있습니까?
Alexander Mills

답변:


39
cmd | while read line; do echo "[ERROR] $line"; done

bash 내장 만 사용하는 장점이 있으므로 프로세스가 덜 생성 / 파기되므로 awk 또는 sed보다 빠르게 처리 해야 합니다.

@tzrik은 멋진 bash 기능을 만들 수도 있다고 지적합니다. 다음과 같이 정의하십시오.

function prepend() { while read line; do echo "${1}${line}"; done; }

다음과 같이 사용할 수 있습니다.

cmd | prepend "[ERROR] "

4
이것은 실제로 프로세스 수를 하나씩 줄입니다. (하지만 정규 sed표현식 ( ) 또는 문자열 분할 ( awk)을 사용 하지 않기 때문에 더 빠를 수도 있습니다 .)
grawity

BTW, 나는 성능에 대해 궁금했고 bash, sed 및 awk를 사용한 간단한 벤치 마크 결과입니다. 약 1000 줄의 텍스트 (dmesg 출력)를 FIFO 파일로 푸시하고 다음과 같이 읽습니다. pastebin.ca/1606844 awk가 승자가 된 것 같습니다. 어떤 아이디어가 있습니까?
Ilya Zakreuski

1
타이밍 테스트를주의해서 실행하십시오. 6 가지 순서로 모두 실행 한 다음 결과를 평균화하십시오. 블록 캐시 효과를 완화하기위한 다른 순서와 백그라운드 중단 / 스케줄링 효과를 완화하기위한 평균.
pjz

이 질문은 "bash"가 아니라 "shell"로 태그됩니다.
fiatjaf 2016 년

1
함수로 감싸기도 쉽다 :function prepend() { while read line; do echo "${1}${line}"; done; }
tzrlk

46

이 시도:

cmd | awk '{print "[ERROR] " $0}'

건배


1
"[ERROR]"는 변수가 될 수 없다는 단점이 있습니다. 전체 표현식은 작은 따옴표로 묶어야하기 때문입니다.
user1071136

4
awk -vT="[ERROR] " '{ print T $0 }'또는awk -vT="[ERROR]" '{ print T " " $0 }'
Tino

2
T="[ERROR] " awk '{ print ENVIRON["T"] $0 }'또는T="[ERROR]" awk '{ print ENVIRON["T"] " " $0 }'
Tino

따옴표의 범위를 종료하여 변수를 역 참조 cmd | awk '{print "['$V]' " $0}'할 수 있습니다.-시작시 한 번 평가되므로 성능 오버 헤드가 없습니다.
robert

13

@grawity에 대한 모든 정당한 인정을 받아, 나는 여기에 가장 좋은 대답 인 것처럼 그의 의견을 답변으로 제출하고 있습니다.

sed 's/^/[ERROR] /' cmd

왜 이것이 bash 솔루션보다 선호됩니까?
user14645

1
나는 그것이 당신의 목적에 달려 있다고 생각합니다. 파일의 모든 행 앞에 단순히 목표를 두는 것이 매우 친숙한 도구를 사용하면 적은 문자로 목표를 달성 할 수 있습니다. 10 줄 bash 스크립트를 선호합니다. awk한 줄 좋은 충분하지만 더 많은 사람들이 잘 알고있는 것으로 생각하는 sed것보다 awk. bash 스크립트는 그것이하는 일에는 좋지만 질문하지 않은 질문에 대답하는 것 같습니다.
Eric Wilson

pjz가 제출 한 답변도 좋은 라이너입니다. 추가 프로그램, 프로세스가 아니며 조금 더 빨리 실행될 있습니다.
14645

3
sed X cmd읽고 cmd실행하지 않습니다. 하나 cmd | sed 's/^/[ERROR] /'또는 sed 's/^/[ERROR] /' <(cmd)cmd > >(sed 's/^/[ERROR] /'). 그러나 후자를 조심하십시오. 그럼에도 불구하고 백그라운드 cmd에서 sed실행 의 리턴 값에 액세스 할 수 있으므로 cmd가 완료된 출력이 표시 될 수 있습니다 . 그래도 파일에 로그인하는 데 좋습니다. 그리고 awk아마도보다 빠릅니다 sed.
티노

좋은. 이 명령은 쉽게 별칭이 지정됩니다. alias lpad="sed 's/^/ /'". 오류 대신 4 개의 선행 공백을 삽입하십시오. 이제 마법의 해트트릭 : ls | lpad | pbcopy같은 4 자리 표시를 함께 LS 출력을 앞에 추가됩니다 마크 다운 에 대한 코드 는 (클립 보드를 붙여 의미 pbcopy이 직접 StackOverflow의 또는 기타 가격 인하 컨텍스트에 맥에, 그것을 움켜). 할 수 없습니다 된 awk 이 하나의 승리 때문에 (첫 번째 시도에) 대답. 동안 읽기 솔루션은 앨리어스 수 있지만 나는이 찾을 나오지도 더 표현. alias
JL Peyret

8

속도 테스트를 수행하기 위해 GitHub 리포지토리 를 만들었습니다 .

결과는 다음과 같습니다.

  • 일반적인 경우 awk가장 빠릅니다. sed조금 느린과 perl많이보다 느린되지 않습니다 sed. 분명히 모든 언어는 텍스트 처리를 위해 고도로 최적화 된 언어입니다.
  • 포크가 우월한 매우 특수한 상황에서 스크립트를 컴파일 된 ksh스크립트 ( shcomp) 로 실행 하면 처리 시간이 훨씬 단축 될 수 있습니다. 대조적으로, bash컴파일 된 ksh스크립트에 비해 느린 속도 입니다.
  • 정적으로 연결된 이진 파일을 만들어서 awk노력할 가치는없는 것 같습니다.

대조적 python으로 느리게 죽었지 만 컴파일 된 사례는 테스트하지 않았습니다. 일반적으로 그러한 스크립팅 사례에서는 수행하지 않기 때문입니다.

다음과 같은 변형이 테스트됩니다.

while read line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST] $line"; done
while read -r line; do echo "[TEST]" $line; done
while read -r line; do echo "[TEST]" "$line"; done
sed 's/^/[TEST] /'
awk '{ print "[TEST] " $0 }'
awk -vT="[TEST] " '{ print T $0 }'
awk -vT="[TEST]" '{ print T " " $0 }'
awk -vT="[TEST]" 'BEGIN { T=T " "; } { print T $0 }'
T="[TEST] " awk '{ print ENVIRON["T"] $0 }'
T="[TEST]" awk '{ print ENVIRON["T"] " " $0 }'
T="[TEST]" awk 'BEGIN { T=ENVIRON["T"] " " } { print T $0 }'
perl -ne 'print "[TEST] $_"'

내 도구 중 하나의 이진 변형 (속도에 최적화되어 있지는 않음) :

./unbuffered.dynamic -cp'[TEST] ' -q ''
./unbuffered.static -cp'[TEST] ' -q ''

파이썬 버퍼링 :

python -uSc 'import sys
for line in sys.stdin: print "[TEST]",line,'

그리고 파이썬은 버퍼링되지 않았습니다.

python -uSc 'import sys
while 1:
 line = sys.stdin.readline()
 if not line: break
 print "[TEST]",line,'

awk -v T="[TEST %Y%m%d-%H%M%S] " '{ print strftime(T) $0 }'타임 스탬프 출력
Tino


3

stdout 및 stderr을 처리하는 솔루션을 원했기 때문에 작성 prepend.sh하여 경로에 넣었습니다.

#!/bin/bash

prepend_lines(){
  local prepended=$1
  while read line; do
    echo "$prepended" "$line"
  done
}

tag=$1

shift

"$@" > >(prepend_lines "$tag") 2> >(prepend_lines "$tag" 1>&2)

이제 prepend.sh "[ERROR]" cmd ..."[ERROR]"앞에 출력을 추가 cmd하고 stderr과 stdout을 별도로 가질 수 있습니다.


나는이 접근법을 시도했지만 >(내가 해결할 수 없었던 서브 쉘 과 관련하여 무언가가있었습니다 . 스크립트가 완료되는 것처럼 보였고 프롬프트가 반환 된 출력이 터미널에 도착 하여 약간 지저분했습니다. 나는 결국 여기에 대답을 생각해 냈습니다. stackoverflow.com/a/25948606/409638
robert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.