bash에서 후행 줄 바꿈을 어떻게 삭제합니까?


10

Perl 's처럼 행동하는 것을 찾고 chomp있습니다. 줄 바꿈 문자 인 경우 마지막 문자를 뺀 입력을 단순히 인쇄하는 명령을 찾고 있습니다.

$ printf "one\ntwo\n" | COMMAND_IM_LOOKING_FOR ; echo " done"
one
two done
$ printf "one\ntwo" | COMMAND_IM_LOOKING_FOR ; echo " done"
one
two done

(Bash와 Zsh의 명령 대체는 모든 후행 줄 바꿈을 삭제하지만 후행 줄 바꿈을 하나만 삭제하는 것을 찾고 있습니다.)

답변:


9

이것은 작동해야합니다 :

printf "one\ntwo\n" | awk 'NR>1{print PREV} {PREV=$0} END{printf("%s",$0)}' ; echo " done"

스크립트는 항상 현재 대신 이전 행을 인쇄하며 마지막 행은 다르게 처리됩니다.

그것이 더 자세하게하는 것 :

  1. NR>1{print PREV} 이전 줄을 인쇄하십시오 (처음 제외).
  2. {PREV=$0}현재 줄을 PREV변수에 저장 합니다.
  3. END{printf("%s",$0)} 마지막으로 줄 바꿈없이 마지막 줄을 인쇄하십시오.

또한 이것은 끝에 최대 하나의 빈 줄을 제거합니다 (제거를 지원하지 않음 "one\ntwo\n\n\n").


15

당신은 perl없이 사용할 수 있습니다 chomp:

$ printf "one\ntwo\n" | perl -0 -pe 's/\n\Z//'; echo " done"
one
two done

$ printf "one\ntwo" | perl -0 -pe 's/\n\Z//'; echo " done"
one
two done

그러나 왜 chomp자체를 사용하지 않습니까?

$ printf "one\ntwo\n" | perl -pe 'chomp if eof'; echo " done"

4

당신이 정확히 동등한 것을 원한다면, chomp내 마음에 오는 첫 번째 방법 은 LatinSuD가 이미 게시awk 솔루션입니다 . 구현 chomp하지는 않지만 chomp자주 사용되는 일반적인 작업을 구현 하는 다른 방법을 추가하겠습니다 .

텍스트를 변수에 넣으면 끝에있는 모든 줄 바꿈이 제거됩니다. 따라서이 모든 명령은 동일한 단일 행 출력을 생성합니다.

echo "$(printf 'one\ntwo') done"
echo "$(printf 'one\ntwo\n') done"
echo "$(printf 'one\ntwo\n\n') done"
echo "$(printf 'one\ntwo\n\n\n\n\n\n\n\n\n\n') done"

파일의 마지막 줄이나 명령 출력에 텍스트를 추가하려는 경우 sed편리 할 수 ​​있습니다. GNU sed 및 대부분의 다른 최신 구현에서는 입력이 줄 바꿈으로 끝나지 않아도 작동합니다 ¹. 그러나 줄 바꿈이 아직 없으면 줄 바꿈이 추가되지 않습니다.

sed '$ s/$/ done/'

¹ 그러나 이것은 모든 sed 구현에서 작동하지 않습니다. sed는 텍스트 처리 도구이며 비어 있지 않고 줄 바꿈 문자로 끝나지 않는 파일은 텍스트 파일이 아닙니다.


최대 하나의 후행 줄 바꿈 만 삭제 chomp하므로 이는와 정확히 동일하지 않습니다 chomp.
Flimm

@Flimm 네, 가장 확실한 정확한 chomp것은 LatinSuD가 이미 게시 한 awk 솔루션입니다. 그러나 대부분의 경우 chomp작업을 수행하기위한 도구 일 뿐이며 일반적인 작업을 수행 할 수있는 방법을 제공합니다. 이를 명확히하기 위해 답변을 업데이트하겠습니다.
Gilles 'SO- 악한 중지'

1

다른 perl접근법. 이것은 전체 입력을 메모리로 읽으므로 많은 양의 데이터에는 적합하지 않을 수 있습니다 (cuonglm 또는 그 awk방법을 사용하십시오 ).

$ printf "one\ntwo\n" | perl -0777pe 's/\n$//'; echo " done"
one
two done

감사합니다, @ StéphaneChazelas. 어떤 이유로 든 이 스위치는 항상 혼란스러워합니다 !
terdon

0

어딘가에 github repo에서 이것을 앗아 갔지만 어디에서 찾을 수 없습니다

후행-빈 줄 삭제 삭제

#!/bin/bash
#
# Delete all trailing blank lines.
# From http://sed.sourceforge.net/sed1line.txt
#
# Version: 1.3.0
# Created: 2011-01-02
# Updated: 2015-01-25
# Contact: Joel Parker Henderson (joel@joelparkerhenderson.com)
# License: GPL
##
set -euf
sed -e :a -e '/^\n*$/{$d;N;ba' -e '}'

0

요약

줄 바꿈없이 줄을 인쇄하고 인쇄 할 다른 줄이있는 경우에만 줄 바꿈을 추가하십시오.

$ printf 'one\ntwo\n' | 

     awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }';   echo " done"

one
two done

다른 솔루션

파일로 작업하는 경우 한 줄의 문자 만 잘라낼 수 있습니다 (줄 바꿈으로 끝나는 경우).

removeTrailNewline () {[[$ (tail -c 1 "$ 1")]] || 잘라 내기 -s-1 "$ 1"; }

파일에서 문자 만 truncate읽은 다음 전체 파일을 읽지 않고 직접 제거 ( ) 해야하므로 빠른 솔루션 입니다.

그러나 stdin (스트림)의 데이터로 작업하는 동안 데이터를 모두 읽어야합니다. 그리고 읽히자 마자 "소비"됩니다. 역 추적 없음 (잘라내 기와 동일). 스트림의 끝을 찾으려면 스트림의 끝을 읽어야합니다. 이 시점에서 입력 스트림을 다시 이동할 수있는 방법이 없으며 데이터는 이미 "소비"되었습니다. 데이터가 있음이 의미 한다 우리는 스트림의 끝과 일치 할 때까지 버퍼의 일부 형태로 저장 될 버퍼의 데이터와 뭔가.

가장 확실한 해결책은 스트림을 파일로 변환하고 해당 파일을 처리하는 것입니다. 그러나 질문은 일종의 스트림 필터를 요구합니다. 추가 파일 사용에 관한 것이 아닙니다.

변하기 쉬운

순진한 솔루션은 전체 입력을 변수로 캡처하는 것입니다.

FilterOne(){ filecontents=$(cat; echo "x");        # capture the whole input
             filecontents=${filecontents%x};       # Remove the "x" added above.
             nl=$'\n';                             # use a variable for newline.
             printf '%s' "${filecontents%"$nl"}";  # Remove newline (if it exists).
       }

printf 'one\ntwo'     | FilterOne ; echo 1done
printf 'one\ntwo\n'   | FilterOne ; echo 2done
printf 'one\ntwo\n\n' | FilterOne ; echo 3done

기억

sed를 사용하여 전체 파일을 메모리에로드 할 수 있습니다. sed에서는 마지막 줄에서 후행 줄 바꿈을 피할 수 없습니다. GNU sed는 후행 줄 바꿈 인쇄를 피할 수 있지만 소스 파일이 이미없는 경우에만 가능합니다. 따라서 간단한 sed는 도움이되지 않습니다.

-z옵션 이있는 GNU awk를 제외하고 :

sed -z 's/\(.*\)\n$/\1/'

awk (임의의 awk)를 사용하면 전체 스트림을 슬러그 처리합니다 printf.

awk '    { content = content $0 RS } 
     END { gsub( "\n$", "", content ); printf( "%s", content ) }
    '

전체 파일을 메모리에로드하는 것은 좋은 생각이 아닐 수 있으며 많은 메모리를 소비 할 수 있습니다.

메모리에 두 줄

awk에서는 변수에 이전 줄을 저장하고 현재 줄을 인쇄하여 루프 당 두 줄을 처리 할 수 ​​있습니다.

awk 'NR>1{print previous} {previous=$0} END {printf("%s",$0)}'

직접 처리

그러나 우리는 더 잘할 수있었습니다.

줄 바꿈없이 현재 줄을 인쇄하고 다음 줄이있을 때만 줄 바꿈을 인쇄하면 한 번에 한 줄씩 처리하며 마지막 줄 에는 줄 바꿈 줄이 없습니다 .

awk 'NR == 1 {printf ( "% s", $ 0); 다음}; {printf ( "\ n % s", $ 0)} '

또는 다른 방법으로 작성하십시오.

awk 'NR>1{ print "" }; { printf( "%s", $0 ) }'

또는:

awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'

그래서:

$ printf 'one\ntwo\n' | awk '{ printf( "%s%s" , NR>1?"\n":"" , $0 ) }'; echo " done"
one
two done
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.