IT

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

lottoking 2020. 6. 8. 08:06
반응형

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


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

0013600   n   t  >  \n

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

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

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


perl -pe 'chomp if eof' filename >filename2

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

perl -pi -e 'chomp if eof' filename

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

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

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


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

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 스크립트를 고려하십시오 .


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및 현재 위치에서 지원은 편집.


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

편집 2 :

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

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


둔한 사람

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

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

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;
}

We open the file for reading and appending; opening for appending means that we are already seeked to the end of the file. We then get the numerical position of the end of the file with tell. We use that number to seek back one character, and then we read that one character. If it's a newline, we truncate the file to the character before that newline, otherwise, we do nothing.

This runs in constant time and constant space for any input, and doesn't require any more disk space, either.


A very simple method for single-line files, requiring GNU echo from coreutils:

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

Here is a nice, tidy Python solution. I made no attempt to be terse here.

This modifies the file in-place, rather than making a copy of the file and stripping the newline from the last line of the copy. If the file is large, this will be much faster than the Perl solution that was chosen as the best answer.

It truncates a file by two bytes if the last two bytes are CR/LF, or by one byte if the last byte is LF. It does not attempt to modify the file if the last byte(s) are not (CR)LF. It handles errors. Tested in Python 2.6.

Put this in a file called "striplast" and 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)

P.S. In the spirit of "Perl golf", here's my shortest Python solution. It slurps the whole file from standard input into memory, strips all newlines off the end, and writes the result to standard output. Not as terse as the Perl; you just can't beat Perl for little tricky fast stuff like this.

Remove the "\n" from the call to .rstrip() and it will strip all white space from the end of the file, including multiple blank lines.

Put this into "slurp_and_chomp.py" and then run python slurp_and_chomp.py < inputfile > outputfile.

import sys

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

Yet another perl WTDI:

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

A fast solution is using the gnu utility truncate:

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

The test will be true if the file does have a trailing new line.

The removal is very fast, truly in place, no new file is needed and the search is also reading from the end just one byte (tail -c1).


$  perl -e 'local $/; $_ = <>; s/\n$//; print' a-text-file.txt

See also Match any character (including newlines) in sed.


Using 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

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

Assuming Unix file type and you only want the last newline this works.

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

It will not work on multiple newlines...

* Works only if the last line is a blank line.


Yet another answer FTR (and my favourite!): echo/cat the thing you want to strip and capture the output through backticks. The final newline will be stripped. For example:

# 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

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.

The only time I've wanted to do this is for code golf, and then I've just copied my code out of the file and pasted it into an echo -n 'content'>file statement.


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

I had a similar problem, but was working with a windows file and need to keep those CRLF -- my solution on linux:

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

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

Should remove any last occurence of \n in file. Not working on huge file (due to sed buffer limitation)


ruby:

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

or:

ruby -ane 'q=p;p=$_;puts q if $.>1;END{print p.strip!}'

This is a good solution if you need it to work with pipes/redirection instead of reading/output from or to a file. This works with single or multiple lines. It works whether there is a trailing newline or not.

# 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

Details:

  • head -c -1 truncates the last character of the string, regardless of what the character is. So if the string does not end with a newline, then you would be losing a character.
  • So to address that problem, we add another command that will add a trailing newline if there isn't one: sed '$s/$//' . The first $ means only apply the command to the last line. s/$// means substitute the "end of the line" with "nothing", which is basically doing nothing. But it has a side effect of adding a trailing newline is there isn't one.

Note: Mac's default head does not support the -c option. You can do brew install coreutils and use ghead instead.

참고URL : https://stackoverflow.com/questions/1654021/how-can-i-delete-a-newline-if-it-is-the-last-character-in-a-file

반응형