ฉันจะลบบรรทัดใหม่ได้อย่างไรถ้าเป็นอักขระตัวสุดท้ายในไฟล์


162

ฉันมีไฟล์บางไฟล์ที่ฉันต้องการลบขึ้นบรรทัดใหม่หากเป็นอักขระตัวสุดท้ายในไฟล์ od -cแสดงให้ฉันเห็นว่าคำสั่งที่ฉันเรียกใช้นั้นเขียนไฟล์ด้วยการขึ้นบรรทัดใหม่:

0013600   n   t  >  \n

ฉันได้ลองเล่นเล่ห์เหลี่ยมเล็กน้อย แต่สิ่งที่ดีที่สุดที่ฉันคิดได้คือไม่ได้เล่นเล่ห์เหลี่ยม:

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

ความคิดใด ๆ วิธีการทำเช่นนี้?


4
ขึ้นบรรทัดใหม่เป็นอักขระเพียงตัวเดียวสำหรับการขึ้นบรรทัดใหม่ของยูนิกซ์ บรรทัดใหม่ของ DOS เป็นอักขระสองตัว แน่นอนตัวอักษร "\ n" เป็นตัวละครสองตัว คุณกำลังมองหาสิ่งใด
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

3
แม้ว่าการเป็นตัวแทนอาจอยู่\nใน linux คือตัวละครตัวหนึ่ง
pavium

10
คุณสามารถอธิบายอย่างละเอียดว่าทำไมคุณถึงต้องการทำสิ่งนี้? ไฟล์ข้อความควรลงท้ายด้วย end-of-line ยกเว้นว่าไฟล์นั้นว่างเปล่าทั้งหมด ดูเหมือนว่าแปลกสำหรับฉันที่คุณต้องการไฟล์ที่ถูกตัดทอน
Thomas Padron-McCarthy

เหตุผลปกติในการทำบางสิ่งเช่นนี้คือการลบเครื่องหมายจุลภาคต่อท้ายออกจากบรรทัดสุดท้ายของไฟล์ CSV ทำงานได้ดี แต่บรรทัดใหม่ต้องได้รับการปฏิบัติแตกต่างกัน
pavium

9
@ ThomasPadron-McCarthy "ในการคำนวณด้วยเหตุผลที่ดีทุกอย่างก็คือการทำอะไรบางอย่างที่นั่นมีเหตุผลที่ดีที่จะไม่ทำมันและทำวีซ่าในทางกลับกัน" -Jesus - "คุณไม่ควรทำอย่างนั้น" เป็นคำตอบที่น่ากลัวไม่ว่าจะมีคำถามอะไร รูปแบบที่ถูกต้องคือ: [วิธีการทำมัน] แต่ [ทำไมมันอาจจะเป็นความคิดที่ดี] #sacrilege
Cory Mawhorter

คำตอบ:


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

หรือเพื่อแก้ไขไฟล์ในสถานที่:

perl -pi -e 'chomp if eof' filename

[หมายเหตุของบรรณาธิการ: -pi -eเดิมที-pieแต่ตามที่ระบุไว้โดยผู้แสดงความคิดเห็นหลายคนและอธิบายโดย @hvd คนหลังใช้งานไม่ได้]

นี่ถูกอธิบายว่าเป็น 'perl blasphemy' ในเว็บไซต์ awk ที่ฉันเห็น

แต่ในการทดสอบก็ใช้งานได้


11
chompคุณสามารถทำให้มันปลอดภัยมากขึ้นโดยใช้ และมันก็เต้นไฟล์
Sinan Ünür

6
การดูหมิ่นแม้ว่ามันจะเป็นไปได้ แต่ก็ใช้งานได้ดีมาก perl -i-pe 'chomp if eof' ชื่อไฟล์ ขอบคุณ.
ทอดด์นกกระทา 'Gen2ly'

13
สิ่งที่ตลกเกี่ยวกับการดูหมิ่นและบาปคือมักจะเกลียดเพราะมันถูกต้อง :)
อีเธอร์

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-> ทำงาน
aditsu ออกเพราะ SE นั้นชั่วร้าย

56

คุณสามารถใช้ประโยชน์จากข้อเท็จจริงที่ว่าการแทนที่คำสั่ง shell ลบอักขระบรรทัดใหม่ต่อท้าย :

รูปแบบง่าย ๆ ที่ทำงานใน 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


3
หมายเหตุหากมีการขึ้นบรรทัดใหม่หลายบรรทัดที่ท้ายไฟล์คำสั่งนี้จะลบทั้งหมด
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

คุณสามารถใช้spongeจาก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
ทางออกที่ดีที่สุดของทั้งหมด ใช้เครื่องมือมาตรฐานที่ลินุกซ์ทุกตัวมีอยู่และมีความกระชับและชัดเจนโดยไม่ต้องมีตัวช่วยสร้างใด ๆ
Dakkaron

2
ทางออกที่ดี การเปลี่ยนแปลงอย่างหนึ่งคือฉันคิดว่าฉันจะใช้truncate --size=-1แทนhead -c -1เพราะมันแค่ปรับขนาดไฟล์อินพุตแทนที่จะอ่านในไฟล์อินพุตเขียนมันเป็นไฟล์อื่นจากนั้นแทนที่ต้นฉบับด้วยไฟล์เอาต์พุต
Karl Wilbur

1
โปรดทราบว่าhead -c -1จะลบอักขระตัวสุดท้ายโดยไม่คำนึงว่าเป็นอักขระขึ้นบรรทัดใหม่หรือไม่นั่นเป็นสาเหตุที่คุณต้องตรวจสอบว่าอักขระตัวสุดท้ายเป็นอักขระขึ้นบรรทัดใหม่ก่อนที่จะลบออกหรือไม่
wisbucky

น่าเสียดายที่ใช้ไม่ได้บน Mac ฉันสงสัยว่ามันไม่ทำงานกับตัวแปร BSD ใด ๆ
Edward Falk

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

แก้ไข 2:

นี่คือawkเวอร์ชัน(แก้ไข)ที่ไม่ได้รวบรวมอาร์เรย์ที่มีขนาดใหญ่:

awk '{if (line) บรรทัดการพิมพ์; บรรทัด = $ 0} END {printf $ 0} 'abc


วิธีดั้งเดิมที่ดีที่จะคิดเกี่ยวกับมัน ขอบคุณเดนนิส
ทอดด์นกกระทา 'Gen2ly'

คุณถูก. ฉันคล้อยตามawkรุ่นของคุณ ใช้เวลาสองออฟเซ็ต (และการทดสอบที่แตกต่างกัน) และฉันใช้มันเพียงครั้งเดียว อย่างไรก็ตามคุณสามารถใช้แทนprintf ORS
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

คุณสามารถสร้างเอ้าท์พุทเป็นhead -n -1 abc | cat <(tail -n 1 abc | tr -d '\n') | ...
ไพพ์ได้

2
การใช้ -c แทน -n สำหรับส่วนหัวและส่วนท้ายควรเร็วกว่านี้
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

ยังดูเหมือนตัวละครมากมายสำหรับฉัน ... เรียนรู้มันช้า :) ทำงานแม้ว่า ขอบคุณ ghostdog
# # # # # # # # # # # # # # # xpss

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
Robin A. Meade

9

วิธีที่ง่ายมากสำหรับไฟล์บรรทัดเดียวต้องการ GNU echo จาก coreutils:

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

นี่เป็นวิธีที่ดีถ้ามันไม่แพงเกินไป (ซ้ำ)

เรื่องนี้มีปัญหาเมื่อ\nมีอยู่ เนื่องจากได้รับการแปลงเป็นบรรทัดใหม่
Chris Stryczynski

ดูเหมือนว่าจะทำงานกับไฟล์หลายบรรทัดได้ด้วย$(...)คำพูด
Thor

แน่นอนต้องอ้างว่า ... /bin/echo -n "$(cat infile)" นอกจากนี้ฉันไม่แน่ใจว่าสิ่งสูงสุดechoหรือเปลือกจะข้าม os / รุ่น shell / distros (ฉันเพิ่ง googling นี้ & มันเป็นหลุมกระต่าย) ดังนั้นฉัน ไม่แน่ใจว่าพกพา (หรือนักแสดง) จริง ๆ แล้วมันจะเป็นอะไรอื่นนอกเหนือจากไฟล์ขนาดเล็ก - แต่สำหรับไฟล์ขนาดเล็กที่ดี
ไมเคิล

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
แต่มีข้อเสียของการไม่ reseting เจ้าของ / สิทธิ์สำหรับไฟล์ ... เอ่อรอที่ ...
ysth

1
verbose แต่ทั้งรวดเร็วและมีประสิทธิภาพดูเหมือนจะเป็นคำตอบเดียวในการแก้ไขไฟล์จริงที่นี่ (และเนื่องจากอาจไม่ชัดเจนสำหรับทุกคน: นี่เป็นสคริปต์Perl )
mklement0

6

นี่เป็นวิธีการแก้ปัญหาของงูหลามที่ดีและเรียบร้อย ฉันไม่พยายามที่จะพูดสั้น ๆ ที่นี่

สิ่งนี้แก้ไขไฟล์ในตำแหน่งแทนที่จะทำสำเนาไฟล์และลอกบรรทัดใหม่จากบรรทัดสุดท้ายของสำเนา หากไฟล์มีขนาดใหญ่จะเร็วกว่าโซลูชัน Perl ที่เลือกไว้เป็นคำตอบที่ดีที่สุด

มันตัดไฟล์สองไบต์ถ้าสองไบต์สุดท้ายคือ CR / LF หรือโดยหนึ่งไบต์ถ้าไบต์สุดท้ายคือ LF จะไม่พยายามแก้ไขไฟล์หากไบต์สุดท้ายไม่ใช่ (CR) LF มันจัดการข้อผิดพลาด ทดสอบใน Python 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)

ป.ล. ด้วยจิตวิญญาณของ "เพิร์ลกอล์ฟ" นี่เป็นวิธีแก้ปัญหางูหลามที่สั้นที่สุดของฉัน มัน slurps ไฟล์ทั้งหมดจากอินพุตมาตรฐานลงในหน่วยความจำตัดบรรทัดใหม่ทั้งหมดออกจากปลายและเขียนผลลัพธ์ไปยังเอาต์พุตมาตรฐาน ไม่กระชับเท่า Perl; คุณไม่สามารถเอาชนะ Perl สำหรับสิ่งที่รวดเร็วหากินเช่นนี้ได้

ลบ "\ 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

การทดสอบจะเป็นจริงหากไฟล์มีบรรทัดใหม่ต่อท้าย

การลบนั้นรวดเร็วมากอย่างแท้จริงไม่ต้องมีไฟล์ใหม่และการค้นหาก็อ่านจากท้ายเพียงหนึ่งไบต์ ( tail -c1)


1
ตัดปลาย: ไม่มีตัวถูกดำเนินการไฟล์
Brian Hannay

2
มันเป็นเพียงแค่หายไปชื่อไฟล์ต่อท้ายในตัวอย่างเช่น[ -z $(tail -c1 filename) ] && truncate -s -1 filename(หรือในการตอบกลับความคิดเห็นอื่น ๆtruncateคำสั่งไม่ได้ทำงานกับ stdin, ชื่อไฟล์ที่ไม่จำเป็นต้องมี)
ไมเคิล


3
$ perl -e 'ท้องถิ่น $ /; $ _ = <>; s / \ n $ //; พิมพ์ 'a-text-file.txt

ดูเพิ่มเติมจับคู่อักขระใด ๆ (รวมถึงการขึ้นบรรทัดใหม่)ด้วย


1
ที่จะขึ้นบรรทัดใหม่ทั้งหมด เทียบเท่ากับtr -d '\n'
หยุดชั่วคราวจนกว่าจะมีประกาศ

สิ่งนี้ใช้ได้ดีเช่นกันอาจดูหมิ่นน้อยกว่าของพาวิเนียม
# # # # # # # # # # # # # # # xpss

Sinan แม้ว่า Linux และ Unix อาจกำหนดไฟล์ข้อความให้ลงท้ายด้วย newline แต่ Windows ก็ไม่ต้องการเช่นนั้น ตัวอย่างเช่น Notepad จะเขียนเฉพาะอักขระที่คุณพิมพ์โดยไม่ต้องเพิ่มอะไรพิเศษในตอนท้าย คอมไพเลอร์ C อาจต้องการไฟล์ต้นฉบับเพื่อสิ้นสุดด้วยการขึ้นบรรทัดใหม่ แต่ไฟล์ต้นฉบับ C ไม่ใช่ไฟล์ข้อความ "เพียง" ดังนั้นจึงสามารถมีข้อกำหนดเพิ่มเติมได้
Rob Kennedy

ในหลอดเลือดดำนั้นตัวทำลายจาวาสคริปต์ / css ส่วนใหญ่จะลบการขึ้นบรรทัดใหม่และยังสร้างไฟล์ข้อความ
ysth

@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หรือวงเล็บรอบ:eof perl -pi -e 's/\n$// if eof' your_file
mklement0

2

สมมติว่าไฟล์ประเภท Unix และคุณต้องการขึ้นบรรทัดใหม่ล่าสุดให้ใช้งานได้เท่านั้น

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

มันจะไม่ทำงานกับการขึ้นบรรทัดใหม่หลายครั้ง ...

* ทำงานได้ก็ต่อเมื่อบรรทัดสุดท้ายเป็นบรรทัดว่าง


นี่คือsedวิธีแก้ปัญหาที่ใช้ได้แม้กับบรรทัดสุดท้ายที่ไม่ว่างเปล่า: stackoverflow.com/a/52047796
wisbucky

1

อีกคำตอบหนึ่งของ FTR (และรายการโปรดของฉัน!): echo / cat สิ่งที่คุณต้องการตัดและจับเอาท์พุทผ่าน backticks ขึ้นบรรทัดใหม่จะถูกปล้น ตัวอย่างเช่น:

# 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

นี่เป็นทางออกที่ดีถ้าคุณต้องการใช้งานกับ pipes / การเปลี่ยนเส้นทางแทนที่จะอ่าน / ส่งออกจากหรือไปยังไฟล์ ใช้ได้กับสายเดียวหรือหลายบรรทัด มันทำงานไม่ว่าจะมีบรรทัดใหม่ต่อท้ายหรือไม่

# 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

ฉันมีปัญหาที่คล้ายกัน แต่ทำงานกับไฟล์ windows และต้องการให้ CRLF เหล่านั้น - โซลูชันของฉันบน linux:

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 ในไฟล์ ไม่ทำงานกับไฟล์ขนาดใหญ่ (เนื่องจากข้อ จำกัด ของบัฟเฟอร์บัฟเฟอร์)


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.