ฉันจะตัดช่องว่างนำหน้าและต่อท้ายจากแต่ละบรรทัดของเอาต์พุตบางรายการได้อย่างไร


155

ฉันต้องการลบช่องว่างและแท็บนำหน้าและส่วนท้ายทั้งหมดออกจากแต่ละบรรทัดในเอาต์พุต

มีเครื่องมือง่ายๆอย่างที่trimฉันสามารถเอาท์พุทของฉันเป็น?

ไฟล์ตัวอย่าง:

test space at back 
 test space at front
TAB at end  
    TAB at front
sequence of some    space in the middle
some empty lines with differing TABS and spaces:





 test space at both ends 

1
สำหรับทุกคนที่กำลังมองหาวิธีแก้ปัญหาเพื่อลบบรรทัดใหม่นั่นเป็นปัญหาที่แตกต่าง การกำหนดบรรทัดใหม่จะสร้างบรรทัดข้อความใหม่ ดังนั้นบรรทัดข้อความไม่สามารถมีบรรทัดใหม่ คำถามที่คุณต้องการถามคือวิธีการลบ newline จากจุดเริ่มต้นหรือจุดสิ้นสุดของสตริง: stackoverflow.com/questions/369758หรือวิธีการลบบรรทัดหรือบรรทัดว่างที่เป็นเพียงช่องว่าง: serverfault.com/questions/252921
โทนี่

คำตอบ:


200
awk '{$1=$1;print}'

หรือสั้นกว่า:

awk '{$1=$1};1'

จะตัดแต่งช่องว่างนำหน้าและต่อท้ายหรืออักขระแท็บ1 และบีบลำดับของแท็บและช่องว่างให้เป็นช่องว่างเดียว

สิ่งนี้ได้ผลเพราะเมื่อคุณกำหนดบางสิ่งให้กับหนึ่งในฟิลด์ให้awkสร้างเรคคอร์ดทั้งหมดใหม่ (ตามที่พิมพ์โดยprint) โดยการเข้าร่วมทุกฟิลด์ ( $1, ... , $NF) ด้วยOFS(เว้นวรรคตามค่าเริ่มต้น)

1 (และอาจเป็นอักขระว่างอื่น ๆ ขึ้นอยู่กับสถานที่และawkการนำไปใช้)


2
อัฒภาคในตัวอย่างที่สองนั้นไม่จำเป็น สามารถใช้:awk '{$1=$1}1'
Brian


น่าสนใจ ... ไม่มีเซมิโคลอนสนับสนุนโดย gawk, mawk และ awk ของ OS X (อย่างน้อยสำหรับรุ่นของฉัน (1.2, 4.1.1 และ 20070501 ตามลำดับ)
Brian

1
สิ่งเดียวที่ฉันไม่ชอบเกี่ยวกับวิธีการนี้คือการที่คุณสูญเสียช่องว่างซ้ำ ๆ ในบรรทัด ตัวอย่างเช่นecho -e 'foo \t bar' | awk '{$1=$1};1'
มิตร

2
echo ' hello ' | xargs
JREAM

44

คำสั่งสามารถย่อตัวอย่างเช่นถ้าคุณใช้ GNU sed:

$ sed 's/^[ \t]*//;s/[ \t]*$//' < file

ตัวอย่าง

นี่คือคำสั่งข้างต้นในการดำเนินการ

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
blahblah

คุณสามารถใช้hexdumpเพื่อยืนยันว่าsedคำสั่งลอกอักขระที่ต้องการได้อย่างถูกต้อง

$ echo -e " \t   blahblah  \t  " | sed 's/^[ \t]*//;s/[ \t]*$//' | hexdump -C
00000000  62 6c 61 68 62 6c 61 68  0a                       |blahblah.|
00000009

คลาสของอักขระ

นอกจากนี้คุณยังสามารถใช้ชื่อคลาสอักขระแทนการแสดงรายการชุด[ \t]ดังนี้:

$ sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//' < file

ตัวอย่าง

$ echo -e " \t   blahblah  \t  " | sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'

เครื่องมือ GNU ส่วนใหญ่ที่ใช้ประโยชน์จากนิพจน์ทั่วไป (regex) สนับสนุนคลาสเหล่านี้

 [[:alnum:]]  - [A-Za-z0-9]     Alphanumeric characters
 [[:alpha:]]  - [A-Za-z]        Alphabetic characters
 [[:blank:]]  - [ \x09]         Space or tab characters only
 [[:cntrl:]]  - [\x00-\x19\x7F] Control characters
 [[:digit:]]  - [0-9]           Numeric characters
 [[:graph:]]  - [!-~]           Printable and visible characters
 [[:lower:]]  - [a-z]           Lower-case alphabetic characters
 [[:print:]]  - [ -~]           Printable (non-Control) characters
 [[:punct:]]  - [!-/:-@[-`{-~]  Punctuation characters
 [[:space:]]  - [ \t\v\f]       All whitespace chars
 [[:upper:]]  - [A-Z]           Upper-case alphabetic characters
 [[:xdigit:]] - [0-9a-fA-F]     Hexadecimal digit characters

การใช้ชุดตัวอักษรเหล่านี้แทนที่จะเป็นตัวอักษรดูเหมือนจะเป็นการสิ้นเปลืองพื้นที่ แต่ถ้าคุณกังวลว่าโค้ดของคุณเป็นแบบพกพาหรือต้องจัดการกับชุดอักขระอื่น (คิดว่าเป็นสากล) คุณอาจต้องการใช้ชื่อคลาส แทน.

อ้างอิง


โปรดทราบว่า[[:space:]]ไม่เท่ากับ[ \t]ในกรณีทั่วไป (unicode ฯลฯ ) [[:space:]]อาจจะช้ากว่ามาก (เนื่องจากมีพื้นที่ว่างหลายประเภทในหน่วย Unicode มากกว่าเพียง' 'และ'\t') สิ่งเดียวกันสำหรับคนอื่น ๆ ทั้งหมด
Olivier Dulac

sed 's/^[ \t]*//'ไม่พกพา ในที่สุด POSIX ก็ต้องการที่จะลบลำดับของช่องว่าง, แบ็กสแลชหรือtตัวละครและนั่นคือสิ่งที่ GNU sedทำเมื่อPOSIXLY_CORRECTอยู่ในสภาพแวดล้อม
Stéphane Chazelas

จะทำอย่างไรถ้าฉันต้องการตัดอักขระขึ้นบรรทัดใหม่ '\ n \ n ข้อความ \ n \ n'
Eugene Biryukov

ฉันชอบวิธีการแก้ปัญหาเพราะการขาดผลข้างเคียงอื่น ๆ เช่นเดียวกับในการแก้ปัญหา awk รูปแบบแรกไม่ทำงานเมื่อฉันพยายามทุบตีใน OSX jsut ตอนนี้ แต่เวอร์ชันคลาสของตัวละครใช้งานได้:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
โทนี่

@EugeneBiryukov เห็นความคิดเห็นของฉันในโพสต์ต้นฉบับ
โทนี่

23

ตามคำแนะนำของStéphane Chazelasในคำตอบที่ยอมรับตอนนี้คุณสามารถ
สร้างสคริปต์/usr/local/bin/trim:

#!/bin/bash
awk '{$1=$1};1'

และให้สิทธิ์ปฏิบัติการไฟล์นั้น:

chmod +x /usr/local/bin/trim

ตอนนี้คุณสามารถส่งผ่านทุกเอาต์พุตไปยังtrimตัวอย่าง:

cat file | trim

(สำหรับความคิดเห็นด้านล่าง: ฉันใช้สิ่งนี้มาก่อน: while read i; do echo "$i"; done
ซึ่งยังใช้งานได้ดี แต่มีประสิทธิภาพน้อยกว่า)


1
โชคดีถ้าไฟล์ของคุณมีขนาดใหญ่และ / หรือมีแบ็กสแลช
don_crissti

1
@don_crissti: คุณสามารถแสดงความคิดเห็นอีกเล็กน้อยได้หรือไม่, วิธีแก้ปัญหาที่เหมาะสมสำหรับไฟล์ขนาดใหญ่และฉันจะแก้ไขวิธีการแก้ปัญหาได้อย่างไรถ้าไฟล์มีแบ็กสแลช?
rubo77

3
คุณจะต้องใช้while read -r lineเพื่อรักษาทับขวาและแม้แล้ว ... สำหรับไฟล์ขนาดใหญ่ / ความเร็วคุณเลือกโซลูชันที่แย่ที่สุด ฉันไม่คิดว่าจะมีอะไรเลวร้ายไปกว่านั้น ดูคำตอบเกี่ยวกับเหตุใดจึงใช้เชลล์ลูปเพื่อประมวลผลข้อความที่ไม่เหมาะสม รวมถึงความคิดเห็นของฉันในคำตอบสุดท้ายที่ฉันเพิ่มลิงค์ไปยังมาตรฐานความเร็ว sedคำตอบที่นี่จะมีการปรับอย่างสมบูรณ์แบบ IMO readและดีกว่า
don_crissti

@don_crissti ... และ / หรือมีบรรทัดที่ขึ้นต้นด้วย-และตามด้วยชุดอักขระ e, e หรือ n 1 ตัวหรือมากกว่าและ / หรือมีอักขระ NUL นอกจากนี้บรรทัดที่ไม่สิ้นสุดหลังจากบรรทัดใหม่สุดท้ายจะถูกข้าม
Stéphane Chazelas

1
คุณสามารถเพิ่มนามแฝงใน / etc / profile (หรือ ~ / .bashrc หรือ ~ / .zshrc ฯลฯ ... ) alias trim = "awk '{\ $ 1 = \ $ 1}; 1'"
Jeff Clayton

22

xargs ที่ไม่มีอาร์กิวเมนต์ให้ทำเช่นนั้น

ตัวอย่าง:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

1
นอกจากนี้ยังทำสัญญาหลายช่องว่างภายในหนึ่งบรรทัดซึ่งไม่ได้รับการร้องขอในคำถาม
roaima

1
@roaima - จริง แต่คำตอบที่ได้รับการยอมรับยังบีบช่องว่าง (ซึ่งไม่ได้รับการร้องขอในคำถาม) ฉันคิดว่าปัญหาที่แท้จริงของที่นี่คือxargsจะไม่สามารถส่งมอบได้หากอินพุตมีแบ็กสแลชและเครื่องหมายคำพูดเดี่ยว
don_crissti

@don_crissti ที่ไม่ได้หมายความว่าคำตอบที่ยอมรับตอบคำถามได้อย่างถูกต้อง แต่ในกรณีนี้ที่นี่มันไม่ได้ถูกตั้งค่าสถานะเป็นข้อแม้ในขณะที่คำตอบที่ยอมรับมันเป็น ฉันหวังว่าจะเน้นความจริงในกรณีที่เกี่ยวข้องกับผู้อ่านในอนาคต
roaima

นอกจากนี้ยังแบ่งคำพูดเดียวอัญประกาศคู่อักขระเครื่องหมายทับขวา นอกจากนี้ยังมีการเรียกใช้หนึ่งรายการขึ้นechoไป การประยุกต์ใช้เสียงสะท้อนบางอย่างจะประมวลผลตัวเลือกและ / หรือแบ็กสแลช ... ซึ่งใช้งานได้กับอินพุตบรรทัดเดียวเท่านั้น
Stéphane Chazelas

17
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

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


1
+1 readสำหรับ ดังนั้นหากคุณไปอ่านในขณะที่ใช้งานได้:cat file | while read i; do echo $i; done
rubo77

1
@rubo ยกเว้นว่าในตัวอย่างของคุณตัวแปร unquote จะถูกประมวลผลอีกครั้งโดยเชลล์ ใช้echo "$i"เพื่อดูผลที่แท้จริงของread
roaima

13

หากคุณจัดเก็บบรรทัดเป็นตัวแปรคุณสามารถใช้ bash เพื่อทำงาน:

ลบช่องว่างนำหน้าจากสตริง:

shopt -s extglob
echo ${text##+([[:space:]])}

ลบช่องว่างต่อท้ายออกจากสตริง:

shopt -s extglob
echo ${text%%+([[:space:]])}

ลบช่องว่างทั้งหมดออกจากสตริง:

echo ${text//[[:space:]]}

การลบ white-space ทั้งหมดออกจากสตริงนั้นไม่เหมือนกับการลบทั้งช่องว่างนำหน้าและช่องว่างท้าย (ตามคำถาม)
catpnosis

ทางออกที่ดีที่สุด - มันต้องการเพียง bash builtins และไม่มีกระบวนการภายนอกส้อม
user259412

2
ดี สคริปต์ทำงานเร็วขึ้นมากหากไม่จำเป็นต้องดึงโปรแกรมภายนอก (เช่น awk หรือ sed) ใช้งานได้กับ ksh รุ่น "modern" (93u +) เช่นกัน
user1683793

9

ในการลบช่องว่างนำหน้าและส่วนท้ายออกจากบรรทัดที่กำหนดด้วยเครื่องมือ 'piped' ฉันสามารถระบุวิธีที่แตกต่างกัน 3 วิธีซึ่งไม่เทียบเท่ากันทั้งหมด ความแตกต่างเหล่านี้เกี่ยวข้องกับช่องว่างระหว่างคำของบรรทัดอินพุต ขึ้นอยู่กับพฤติกรรมที่คาดหวังคุณจะตัดสินใจเลือก

ตัวอย่าง

เพื่ออธิบายความแตกต่างลองพิจารณาบรรทัดอินพุตดัมมี่นี้:

"   \t  A   \tB\tC   \t  "

TR

$ echo -e "   \t  A   \tB\tC   \t  " | tr -d "[:blank:]"
ABC

trเป็นคำสั่งง่ายๆ ในกรณีนี้จะลบช่องว่างหรืออักขระการจัดระเบียบใด ๆ

awk

$ echo -e "   \t  A   \tB\tC   \t  " | awk '{$1=$1};1'
A B C

awk ลบช่องว่างด้านหน้าและด้านหลังและบีบให้มีช่องว่างเดียวทุกช่องว่างระหว่างคำ

sed

$ echo -e "   \t  A   \tB\tC   \t  " | sed 's/^[ \t]*//;s/[ \t]*$//'
A       B   C

ในกรณีนี้sedลบช่องว่างนำหน้าและปรับช่องว่างโดยไม่ต้องแตะช่องว่างระหว่างคำ

สังเกต:

ในกรณีของคำเดียวต่อบรรทัดtrให้ทำงาน


ไม่มีการตัดแต่งข้อมูลนี้ตามหลัง / นำขึ้นบรรทัดใหม่
บำรุงรักษาสูง

+1 สำหรับรายการโซลูชันที่มีเอาต์พุต (บางครั้งไม่คาดคิด)
โทนี่

@ user61382 นี้ค่อนข้างช้า แต่เห็นความคิดเห็นของฉันในโพสต์ต้นฉบับ
โทนี่

@ highmaintenance: use [:space:]แทน [: blank:] สำหรับคำสั่งtrเช่น: ... | tr -d [:space:]เพื่อลบบรรทัดใหม่ด้วย (ดู: man tr)
tron5

6

sed เป็นเครื่องมือที่ดีสำหรับการที่:

                        # substitute ("s/")
sed 's/^[[:blank:]]*//; # parts of lines that start ("^")  with a space/tab 
     s/[[:blank:]]*$//' # or end ("$") with a space/tab
                        # with nothing (/)

คุณสามารถใช้มันสำหรับกรณีของคุณได้ทั้งการไพพ์ในข้อความเช่น

<file sed -e 's/^[[...

หรือโดยการทำ 'อินไลน์' หากคุณsedเป็น GNU:

sed -i 's/...' file

แต่เปลี่ยนแหล่งที่มาของวิธีนี้คือ "อันตราย" เป็นมันอาจจะไม่สามารถกู้คืนเมื่อมันไม่ทำงานขวา (หรือแม้กระทั่งเมื่อมันไม่!), การสำรองข้อมูลเพื่อครั้งแรก (หรือใช้-i.bakซึ่งยังมีผลประโยชน์ที่จะพกพาบาง BSD seds) !


2

คำสั่งแปลจะทำงานได้

cat file | tr -d [:blank:]

4
คำสั่งนี้ไม่ถูกต้องเนื่องจากจะลบช่องว่างทั้งหมดออกจากไฟล์ไม่ใช่แค่นำหน้า / ต่อท้ายช่องว่าง
Brian Redbeard

@BrianRedbeard คุณถูกต้อง นี่ยังคงเป็นคำตอบที่มีประโยชน์สำหรับสตริงเสาหินโดยไม่มีช่องว่าง
Anthony Rutledge

0

หากสตริงที่พยายามตัดแต่งนั้นสั้นและต่อเนื่อง / ต่อเนื่องกันคุณสามารถผ่านมันเป็นพารามิเตอร์ไปยังฟังก์ชัน bash ใด ๆ ได้:

    trim(){
        echo $@
    }

    a="     some random string   "

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