줄 바꿈이 파일의 마지막 문자 인 경우 어떻게 삭제합니까?
마지막 줄 바꿈이 파일의 마지막 문자 인 경우 삭제하려는 일부 파일이 있습니다. 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
노트 :
- 경우
in.txt
에 끝 여러 줄 바꿈 문자, 명령 치환은 제거 모든 중 - 덕분에, @Sparhawk을. 후행 줄 바꿈 이외의 공백 문자는 제거하지 않습니다. - 이 방법 은 전체 입력 파일을 메모리로 읽으 므로 더 작은 파일에만 권장됩니다.
printf %s
줄 바꿈이 출력에 추가되지 않도록합니다 (비표준의 POSIX 호환 대안입니다echo -n
. http://pubs.opengroup.org/onlinepubs/009696799/utilities/echo.html 및 https : //unix.stackexchange 참조). com / a / 65819 )
다른 답변에 가이드 :
Perl 을 사용할 수 있다면 허용되는 답변을 찾으 십시오. 간단하고 메모리 효율적입니다 (전체 입력 파일을 한 번에 읽지 않음).
그렇지 않으면, ghostdog74의 Awk 답변을 고려 하십시오 - 모호하지만 메모리 효율적입니다 . 더 읽기 상당 (POSIX 호환)입니다 :
awk 'NR > 1 { print prev } { prev=$0 } END { ORS=""; print }' in.txt
END
블록 에서 최종 행을 처리 할 수 있도록 인쇄가 한 줄 지연되어\n
출력 레코드 구분 기호 (OFS
)를 빈 문자열 로 설정하여 후행없이 인쇄 합니다.
원본을 대체하는 임시 파일을 작성하는 대신 실제로 편집 하는 상세하지만 빠르고 강력한 솔루션을 원한다면 jrockway의 Perl 스크립트를 고려하십시오 .
head
GNU 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"편집을 위해 sponge
from 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 seek
ed 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:
$ - 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.
'IT' 카테고리의 다른 글
Java에서 &와 &&의 차이점은 무엇입니까? (0) | 2020.06.08 |
---|---|
이진 파일을 비교하여 동일한 지 확인하는 방법은 무엇입니까? (0) | 2020.06.08 |
curl을 사용하여 PHP에서 HTTP 코드 가져 오기 (0) | 2020.06.08 |
MySQL에서 현재 시간에 2 시간을 추가 하시겠습니까? (0) | 2020.06.08 |
임대 Blob이 포함 된 Azure 저장소 계정을 어떻게 삭제합니까? (0) | 2020.06.08 |