줄 바꿈이 파일의 마지막 문자 인 경우 어떻게 삭제합니까?


162

마지막 줄 바꿈이 파일의 마지막 문자 인 경우 삭제하려는 일부 파일이 있습니다. od -c내가 실행하는 명령이 새로운 줄로 파일을 작성한다는 것을 보여줍니다.

0013600   n   t  >  \n

sed로 몇 가지 트릭을 시도했지만 생각할 수있는 최선은 트릭을 수행하지 않는 것입니다.

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

이 작업을 수행하는 방법에 대한 아이디어가 있습니까?


4
개행 문자는 유닉스 개행 문자의 한 문자입니다. DOS 줄 바꿈은 두 문자입니다. 물론 리터럴 "\ n"은 두 문자입니다. 실제로 어떤 것을 찾고 있습니까?
추후 공지가있을 때까지 일시 중지되었습니다.

3
비록 그 표현은 \n, 리눅스에서 하나의 문자입니다
pavium

10
왜 이것을하고 싶은지 자세히 설명해 주시겠습니까? 텍스트 파일이 있습니다 가정 그들이 완전히 비어하지 않는 한, 줄 끝으로 종료합니다. 당신이 그런 잘린 파일을 갖고 싶어한다는 것이 이상하게 보입니다.
Thomas Padron-McCarthy

작업을위한 일반적인 이유는 무엇인가 이와 같은 CSV 파일의 마지막 줄에서 뒤에 쉼표를 삭제하는 것입니다. Sed는 잘 작동하지만 줄 바꿈은 다르게 처리해야합니다.
pavium

9
@ ThomasPadron-McCarthy "컴퓨팅에서, 모든 좋은 이유 때문에 무언가를해야하는 이유는 그렇지 않은 이유도 있습니다." 예수- "그렇게해서는 안된다"는 질문에 상관없이 끔찍한 대답입니다. 올바른 형식은 : [방법]이지만 [ 나쁜 생각 있는 이유 ]입니다. #sacrilege
Cory Mawhorter

답변:


223
perl -pe 'chomp if eof' filename >filename2

또는 파일을 제자리에 편집하려면 다음을 수행하십시오.

perl -pi -e 'chomp if eof' filename

[편집자 주 : -pi -e원래 -pie는 였지만 여러 주석가가 언급하고 @hvd가 설명했듯이 후자는 작동하지 않습니다.]

이것은 내가 본 awk 웹 사이트에서 '펄 신성 모독'으로 묘사되었습니다.

그러나 테스트에서 효과가있었습니다.


11
을 사용하여 더 안전하게 만들 수 있습니다 chomp. 그리고 파일을 뛰어 넘는 것보다 낫습니다.
Sinan Ünür

6
그것이 신성 모독이지만, 그것은 아주 잘 작동합니다. perl -i -pe 'chomp if eof'파일 이름. 감사합니다.
Todd Partridge 'Gen2ly'2009

13
신성 모독과 이단에 관한 재미있는 점은 그것이 정확하기 때문에 보통 미워한다는 것입니다. :)
Ether

8
작은 수정 : perl -pi -e 'chomp if eof' filename,을 사용 하여 임시 파일을 생성하는 대신 내부 파일을 편집 할 수 있습니다
Romuald Brunet

7
perl -pie 'chomp if eof' filename-> perl 스크립트 "chomp if eof"를 열 수 없습니다 : 해당 파일이나 디렉토리가 없습니다. perl -pi -e 'chomp if eof' filename-> 작품
SE 악이기 때문에 aditsu 종료

56

명령 대체가 후행 줄 바꾸기 문자를 제거 한다는 사실을 이용할 수 있습니다 .

bash, ksh, zsh에서 작동하는 간단한 형식 :

printf %s "$(< in.txt)" > out.txt

휴대용 (POSIX 호환) 대안 (약간 덜 효율적) :

printf %s "$(cat in.txt)" > out.txt

노트 :


다른 답변에 가이드 :

  • Perl 을 사용할 수 있다면 허용되는 답변을 찾으 십시오. 간단하고 메모리 효율적입니다 (전체 입력 파일을 한 번에 읽지 않음).

  • 그렇지 않으면, ghostdog74의 Awk 답변을 고려 하십시오 - 모호하지만 메모리 효율적입니다 . 더 읽기 상당 (POSIX 호환)입니다 :

    • awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txt
    • END블록 에서 최종 행을 처리 할 수 ​​있도록 인쇄가 한 줄 지연되어 \n출력 레코드 구분 기호 ( OFS)를 빈 문자열 로 설정하여 후행없이 인쇄 합니다.
  • 원본을 대체하는 임시 파일을 작성하는 대신 실제로 편집 하는 상세하지만 빠르고 강력한 솔루션을 원한다면 jrockway의 Perl 스크립트를 고려하십시오 .


3
NB 파일 끝에 줄 바꿈이 여러 개 있으면이 명령은 줄 바꿈을 모두 삭제합니다.
Sparhawk

47

headGNU coreutils 에서이 작업을 수행 할 수 있으며 파일 끝과 관련된 인수를 지원합니다. 마지막 바이트 사용을 피하려면 :

head -c -1

끝나는 줄 바꿈을 테스트하려면 tail및 을 사용할 수 있습니다 wc. 다음 예제는 결과를 임시 파일에 저장 한 후 원본을 덮어 씁니다.

if [[ $(tail -c1 file | wc -l) == 1 ]]; then
  head -c -1 file > file.tmp
  mv file.tmp file
fi

"in-place"편집을 위해 spongefrom moreutils을 사용할 수도 있습니다 .

[[ $(tail -c1 file | wc -l) == 1 ]] && head -c -1 file | sponge file

.bashrc파일에 이것을 넣어서 일반적인 재사용 가능한 기능을 만들 수도 있습니다.

# Example:  remove-last-newline < multiline.txt
function remove-last-newline(){
    local file=$(mktemp)
    cat > $file
    if [[ $(tail -c1 $file | wc -l) == 1 ]]; then
        head -c -1 $file > $file.tmp
        mv $file.tmp $file
    fi
    cat $file
}

최신 정보

에서 언급 한 바와 같이 KarlWilbur 의견과에서 사용 Sorentar의 대답 , truncate --size=-1대체 할 수 head -c-1및 현재 위치에서 지원은 편집.


3
지금까지 최고의 솔루션. sed 또는 perl 마법사없이 실제로 모든 Linux 배포에 포함되어 있고 간결하고 명확한 표준 도구를 사용합니다.
Dakkaron

2
좋은 해결책. 한 가지 변경 사항은 입력 파일을 읽지 않고 다른 파일에 기록 한 다음 원본을 출력 파일로 바꾸지 않고 입력 파일의 크기를 조정하기 때문에 truncate --size=-1대신에 사용한다고 생각 head -c -1합니다.
Karl Wilbur

1
참고 head -c -1제거하기 전에 마지막 문자가 줄 바꿈이 있는지 여부를 확인해야 할 이유가 개행 문자인지 아닌지에 관계없이 마지막 문자를 제거, 즉이다.
wisbucky

불행히도 Mac에서는 작동하지 않습니다. BSD 변형에서 작동하지 않는 것 같습니다.
에드워드 포크

16
head -n -1 abc > newfile
tail -n 1 abc | tr -d '\n' >> newfile

편집 2 :

다음은 잠재적으로 거대한 배열을 축적하지 않는 awk버전 (수정) 입니다.

awk '{if (라인) 인쇄 라인; line = $ 0} 끝 {printf $ 0} 'abc


그것에 대해 생각하는 좋은 독창적 인 방법. 고마워 데니스
Todd Partridge 'Gen2ly'2009

당신이 올바른지. 나는 당신의 awk버전을 연기합니다 . 그것은 걸립니다 오프셋 (그리고 다른 시험)와 나는 단지 하나를 데 사용합니다. 그러나 printf대신 사용할 수 있습니다 ORS.
추후 공지가있을 때까지 일시 중지되었습니다.

프로세스 대체를 사용하여 출력을 파이프로 만들 수 있습니다.head -n -1 abc | cat <(tail -n 1 abc | tr -d '\n') | ...
BCoates

2
머리와 꼬리에 -n 대신 -c를 사용하는 것이 훨씬 빠릅니다.
rudimeier

1
나를 위해 head -n -1 abc는 파일의 마지막 실제 줄을 제거하여 후행 줄 바꿈을 남겼습니다. head -c -1 abc가 더 잘 작동하는 것 같습니다
ChrisV

10

둔한 사람

   awk '{q=p;p=$0}NR>1{print q}END{ORS = ""; print p}' file

아직도 나에게 많은 캐릭터처럼 보입니다 ... 천천히 배우는 것 :). 그래도 작업을 수행합니다. 고스트 독 감사합니다.
Todd Partridge 'Gen2ly'2009

1
awk '{ prev_line = line; line = $0; } NR > 1 { print prev_line; } END { ORS = ""; print line; }' file이것은 읽기 쉬워야합니다.
Yevhen Pavliuk

어떻습니까 : awk 'NR>1 {print p} {p=$0} END {printf $0}' file.
Isaac

@sorontar 첫 번째 인수 printf형식 인수입니다. 따라서 입력 파일에과 같은 형식 지정자로 해석 될 수있는 것이 %d있으면 오류가 발생합니다. 수정 사항은로 변경하는 것입니다printf "%s" $0
로빈 A. 미드

9

coreutils의 GNU echo가 필요한 단일 행 파일을위한 매우 간단한 방법 :

/bin/echo -n $(cat $file)

너무 비싸지 않으면 (반복적 인) 괜찮은 방법입니다.

\n존재하는 경우 문제 가 있습니다. 새 줄로 변환됩니다.
Chris Stryczynski

또한 멀티 라인 파일을 작동하는 것 같다 그것은 $(...)인용
토르

확실히 인용해야합니다 ... /bin/echo -n "$(cat infile)" 또한, 최대 len echo또는 쉘이 os / shell 버전 / distros에 있는지 확실하지 않습니다 (나는 단지 인터넷 검색 중이며 토끼 구멍이었습니다). 실제로 작은 파일 이외의 다른 파일에 대한 휴대 성 (또는 성능)이 확실하지는 않지만 작은 파일에는 좋습니다.
마이클

8

제대로하려면 다음과 같은 것이 필요합니다.

use autodie qw(open sysseek sysread truncate);

my $file = shift;
open my $fh, '+>>', $file;
my $pos = tell $fh;
sysseek $fh, $pos - 1, 0;
sysread $fh, my $buf, 1 or die 'No data to read?';

if($buf eq "\n"){
    truncate $fh, $pos - 1;
}

읽고 추가하기 위해 파일을 엽니 다. 추가를 위해 여는 seek것은 파일의 끝 부분에 이미 들어 갔음을 의미 합니다. 그런 다음 파일 끝의 숫자 위치를로 얻습니다 tell. 이 숫자를 사용하여 한 문자를 찾은 다음 그 문자를 읽습니다. 줄 바꿈이면 파일을 줄 바꿈 앞의 문자로 자릅니다. 그렇지 않으면 아무것도하지 않습니다.

이것은 모든 입력에 대해 일정한 시간과 일정한 공간에서 실행되며 더 이상 디스크 공간이 필요하지 않습니다.


2
그러나 파일에 대한 소유권 / 권한을 재설정하지 않는 단점이 있습니다 ... err, 잠깐만 ...
ysth

1
장황하지만 빠르면서도 강력합니다. 여기에서 유일한 실제 위치 내 파일 편집 답변 인 것 같습니다 (모든 사람에게 명백하지는 않기 때문에 : 이것은 Perl 스크립트입니다).
mklement0

6

다음은 깔끔하고 깔끔한 Python 솔루션입니다. 나는 여기에서 간결한 시도를하지 않았다.

파일 복사본을 만들고 복사본의 마지막 줄에서 줄 바꿈을 제거하는 대신 파일을 수정합니다. 파일이 크면 이것이 가장 좋은 답변으로 선택된 Perl 솔루션보다 훨씬 빠릅니다.

마지막 2 바이트가 CR / LF 인 경우 파일을 2 바이트로 자르거나 마지막 바이트가 LF 인 경우 1 바이트 씩 자릅니다. 마지막 바이트가 (CR) LF가 아닌 경우 파일 수정을 시도하지 않습니다. 오류를 처리합니다. 파이썬 2.6에서 테스트되었습니다.

이것을 "striplast"라는 파일에 넣고 chmod +x striplast.

#!/usr/bin/python

# strip newline from last line of a file


import sys

def trunc(filename, new_len):
    try:
        # open with mode "append" so we have permission to modify
        # cannot open with mode "write" because that clobbers the file!
        f = open(filename, "ab")
        f.truncate(new_len)
        f.close()
    except IOError:
        print "cannot write to file:", filename
        sys.exit(2)

# get input argument
if len(sys.argv) == 2:
    filename = sys.argv[1]
else:
    filename = "--help"  # wrong number of arguments so print help

if filename == "--help" or filename == "-h" or filename == "/?":
    print "Usage: %s <filename>" % sys.argv[0]
    print "Strips a newline off the last line of a file."
    sys.exit(1)


try:
    # must have mode "b" (binary) to allow f.seek() with negative offset
    f = open(filename, "rb")
except IOError:
    print "file does not exist:", filename
    sys.exit(2)


SEEK_EOF = 2
f.seek(-2, SEEK_EOF)  # seek to two bytes before end of file

end_pos = f.tell()

line = f.read()
f.close()

if line.endswith("\r\n"):
    trunc(filename, end_pos)
elif line.endswith("\n"):
    trunc(filename, end_pos + 1)

추신 "펄 골프"의 정신으로, 여기 제가 가장 짧은 파이썬 솔루션이 있습니다. 전체 파일을 표준 입력에서 메모리로 넘기고 모든 줄 바꿈을 끝까지 제거하고 결과를 표준 출력에 씁니다. 펄만큼 간결하지는 않다. 이런 까다로운 속임수로 펄을 이길 수는 없습니다.

호출에서 "\ n"을 제거하면 .rstrip()여러 개의 빈 줄을 포함하여 파일 끝에서 모든 공백이 제거됩니다.

이것을 "slurp_and_chomp.py"에 넣고 실행하십시오 python slurp_and_chomp.py < inputfile > outputfile.

import sys

sys.stdout.write(sys.stdin.read().rstrip("\n"))

os.path.isfile ()은 파일 존재에 대해 알려줍니다. :) 다른 오류를 많이 잡을 제외 / 시도를 할 수 사용
데니스 Barmenkov

5

빠른 솔루션은 gnu 유틸리티를 사용하고 있습니다 truncate.

[ -z $(tail -c1 file) ] && truncate -s-1 file

파일에 줄 바꿈이 있으면 테스트가 적용됩니다.

제거는 매우 빠르며, 실제로 제자리에 있으며, 새로운 파일이 필요하지 않으며 검색은 끝에서 1 바이트 ( tail -c1) 만 읽습니다 .


1
자르기 : 누락 된 파일 피연산자
Brian Hannay

2
예에서 마지막 파일 이름이 누락되었습니다. 즉, [ -z $(tail -c1 filename) ] && truncate -s -1 filename다른 주석에 대한 응답으로 truncate명령이 stdin과 작동하지 않으며 파일 이름이 필요합니다.
michael

4

또 다른 펄 WTDI :

perl -i -p0777we's/\n\z//' filename

3
$ perl -e 'local $ /; $ _ = <>; s / \ n $ //; 인쇄 '텍스트 파일 .txt

sed의 모든 문자 일치 (줄 바꾸기 포함) 도 참조하십시오 .


1
그것은 모든 줄 바꿈을 수행합니다. 상당은tr -d '\n'
추후 공지가있을 때까지 일시 중지.

이것도 잘 작동하며 아마도 파튬보다 덜 모독 적입니다.
Todd Partridge 'Gen2ly'10

Sinan은 Linux와 Unix가 텍스트 파일을 줄 바꿈으로 정의 할 수 있지만 Windows에는 그러한 요구 사항이 없습니다. 예를 들어 메모장은 끝에 추가 항목을 추가하지 않고 입력 한 문자 만 씁니다. C 컴파일러는 줄 바꿈으로 끝나기 위해 소스 파일이 필요할 수 있지만 C 소스 파일은 텍스트 파일이 아니기 때문에 추가 요구 사항이있을 수 있습니다.
Rob Kennedy

그 맥락에서 대부분의 javascript / css 축소 기는 후행 줄 바꿈을 제거하지만 텍스트 파일을 생성합니다.
ysth 2009

@Rob Kennedy 및 @ysth : 왜 그러한 파일이 실제로 텍스트 파일이 아닌지에 대한 흥미로운 주장이 있습니다.
Sinan Ünür

2

dd 사용 :

file='/path/to/file'
[[ "$(tail -c 1 "${file}" | tr -dc '\n' | wc -c)" -eq 1 ]] && \
    printf "" | dd  of="${file}" seek=$(($(stat -f "%z" "${file}") - 1)) bs=1 count=1
    #printf "" | dd  of="${file}" seek=$(($(wc -c < "${file}") - 1)) bs=1 count=1

2
perl -pi -e 's/\n$// if(eof)' your_file

허용되는 답변과 사실상 동일하지만 Perl 이외의 사용자에게는 개념 상 분명합니다. : g또는 괄호 가 필요하지 않습니다 . eofperl -pi -e 's/\n$// if eof' your_file
mklement0

2

유닉스 파일 형식을 가정하고 마지막 줄 바꿈 만 원한다고 가정하십시오.

sed -e '${/^$/d}'

여러 줄 바꿈에서는 작동하지 않습니다 ...

* 마지막 줄이 빈 줄인 경우에만 작동합니다.


여기의 sed공백이 아닌 마지막 줄에 대해서도 작동 솔루션 : stackoverflow.com/a/52047796
wisbucky

1

또 다른 대답은 FTR (및 내가 좋아하는 것!)입니다. 백틱을 통해 출력을 제거하고 캡처하려는 것을 에코 / 고양이하십시오. 마지막 줄 바꿈이 제거됩니다. 예를 들면 다음과 같습니다.

# Sadly, outputs newline, and we have to feed the newline to sed to be portable
echo thingy | sed -e 's/thing/sill/'

# No newline! Happy.
out=`echo thingy | sed -e 's/thing/sill/'`
printf %s "$out"

# Similarly for files:
file=`cat file_ending_in_newline`
printf %s "$file" > file_no_newline

1
cat-printf 콤보가 우연히 발견되었습니다 (반대적인 행동을 취하려고했습니다). 이렇게하면 마지막 줄뿐만 아니라 마지막 줄 바꿈도 모두 제거됩니다 .
technosaurus

1

POSIX SED :

'$ {/ ^ $ / d}'

$ - match last line


{ COMMANDS } - A group of commands may be enclosed between { and } characters. This is particularly useful when you want a group of commands to be triggered by a single address (or address-range) match.

마지막 줄이 비어있는 경우에만 제거 할 것이라고 생각합니다. 마지막 줄이 비어 있지 않으면 후행 줄 바꿈이 제거되지 않습니다. 예를 들어, echo -en 'a\nb\n' | sed '${/^$/d}'아무것도 제거하지 않습니다. echo -en 'a\nb\n\n' | sed '${/^$/d}'마지막 줄 전체가 비어 있기 때문에 제거됩니다.
wisbucky

1

파일을 읽거나 출력하는 대신 파이프 / 리디렉션으로 작업해야하는 경우 좋은 솔루션입니다. 이것은 한 줄 또는 여러 줄로 작동합니다. 후행 줄 바꿈이 있는지 여부에 관계없이 작동합니다.

# with trailing newline
echo -en 'foo\nbar\n' | sed '$s/$//' | head -c -1

# still works without trailing newline
echo -en 'foo\nbar' | sed '$s/$//' | head -c -1

# read from a file
sed '$s/$//' myfile.txt | head -c -1

세부:

  • head -c -1문자가 무엇이든 관계없이 문자열의 마지막 문자를 자릅니다. 따라서 문자열이 줄 바꿈으로 끝나지 않으면 문자가 손실됩니다.
  • 따라서이 문제를 해결하기 위해 후행 줄 바꿈이없는 다른 명령을 추가합니다 sed '$s/$//'. 첫 번째 $는 마지막 줄에만 명령을 적용한다는 의미입니다. s/$//"줄 끝"을 "아무것도 없음"으로 바꾸는 것을 의미합니다. 기본적으로 아무것도하지 않습니다. 그러나 후행 줄 바꿈을 추가하지 않으면 부작용이 있습니다.

참고 : Mac의 기본값 head-c옵션을 지원하지 않습니다 . 대신 대신 brew install coreutils사용할 수 있습니다 ghead.


0

내가 이것을하고 싶었던 유일한 시간은 코드 골프를위한 것입니다. 그런 다음 코드를 파일에서 복사하여 echo -n 'content'>file명령문에 붙여 넣었습니다 .


반쯤; 여기에 완전한 접근 방식 .
mklement0

0
sed ':a;/^\n*$/{$d;N;};/\n$/ba' file

작동하지만 후행 줄 바꿈을 모두 제거 합니다 .
mklement0

0

비슷한 문제가 있었지만 Windows 파일로 작업하고 있었고 Linux에서 내 솔루션 인 CRLF를 유지해야합니다.

sed 's/\r//g' orig | awk '{if (NR>1) printf("\r\n"); printf("%s",$0)}' > tweaked

0
sed -n "1 x;1 !H
$ {x;s/\n*$//p;}
" YourFile

파일에서 \ n의 마지막 항목을 제거해야합니다. 대용량 파일에서 작동하지 않음 (sed 버퍼 제한으로 인해)


0

루비:

ruby -ne 'print $stdin.eof ? $_.strip : $_'

또는:

ruby -ane 'q=p;p=$_;puts q if $.>1;END{print p.strip!}'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.