Làm cách nào để cắt khoảng trắng hàng đầu và dấu kiểm từ mỗi dòng của một số đầu ra?


155

Tôi muốn xóa tất cả các dấu cách và dấu cách hàng đầu và dấu kiểm khỏi mỗi dòng trong một đầu ra.

Có một công cụ đơn giản như trimtôi có thể dẫn đầu ra của mình vào không?

Tệp ví dụ:

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
Đối với bất cứ ai đang tìm kiếm một giải pháp để loại bỏ dòng mới, đây là một vấn đề khác. Theo định nghĩa, một dòng mới tạo ra một dòng văn bản mới. Do đó, một dòng văn bản không thể chứa một dòng mới. Câu hỏi bạn muốn hỏi là làm thế nào để xóa một dòng mới từ đầu hoặc cuối chuỗi: stackoverflow.com/questions/369758 hoặc cách xóa các dòng hoặc dòng trống chỉ là khoảng trắng: serverfault.com/questions/252921
Tony

Câu trả lời:


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

hoặc ngắn hơn:

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

Sẽ cắt không gian hàng đầu và dấu hoặc ký tự tab 1 và cũng nén các chuỗi tab và khoảng trắng vào một khoảng trống.

Điều đó hoạt động bởi vì khi bạn gán một cái gì đó cho một trong các trường , hãy awkxây dựng lại toàn bộ bản ghi (như được in bởi print) bằng cách nối tất cả các trường ( $1, ..., $NF) với OFS(khoảng trắng theo mặc định).

1 (và có thể các ký tự trống khác tùy thuộc vào ngôn ngữ và cách awktriển khai)


2
Dấu chấm phẩy trên ví dụ thứ hai là không cần thiết. Có thể sử dụng:awk '{$1=$1}1'
Brian


Thật thú vị ... Không có dấu chấm phẩy nào được hỗ trợ bởi awk của gawk, mawk và OS X. (Ít nhất là cho các phiên bản của tôi (lần lượt là 1.2, 4.1.1 và 20070501)
Brian

1
Điều duy nhất tôi không thích về cách tiếp cận này là bạn mất các khoảng trắng lặp lại trong dòng. Ví dụ:echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly

2
echo ' hello ' | xargs
JREAM

44

Lệnh có thể được cô đọng như vậy nếu bạn đang sử dụng GNU sed:

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

Thí dụ

Đây là lệnh trên trong hành động.

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

Bạn có thể sử dụng hexdumpđể xác nhận rằng sedlệnh đang tước chính xác các ký tự mong muốn.

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

Các lớp nhân vật

Bạn cũng có thể sử dụng tên lớp nhân vật thay vì liệt kê theo nghĩa đen các bộ như thế này [ \t]:

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

Thí dụ

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

Hầu hết các công cụ GNU sử dụng các biểu thức chính quy (regex) đều hỗ trợ các lớp này.

 [[: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

Sử dụng các bộ này thay cho các bộ chữ luôn có vẻ như lãng phí không gian, nhưng nếu bạn quan tâm đến mã của mình là di động hoặc phải xử lý các bộ ký tự thay thế (nghĩ quốc tế), thì bạn có thể muốn sử dụng tên lớp thay thế.

Người giới thiệu


Lưu ý rằng [[:space:]]không tương đương với [ \t]trong trường hợp chung (unicode, v.v.). [[:space:]]có lẽ sẽ chậm hơn nhiều (vì có nhiều loại khoảng trắng trong unicode hơn chỉ ' ''\t'). Điều tương tự cho tất cả những người khác.
Olivier Dulac

sed 's/^[ \t]*//'không phải là di động. Về cơ bản, POSIX thậm chí còn yêu cầu xóa một chuỗi không gian, dấu gạch chéo ngược hoặc tký tự và đó là điều GNU sedcũng làm khi POSIXLY_CORRECTở trong môi trường.
Stéphane Chazelas

Nếu tôi muốn cắt các ký tự mới thì sao? '\ n \ n văn bản \ n \ n'
Eugene Biryukov

Tôi thích giải pháp sed vì thiếu các tác dụng phụ khác như trong giải pháp awk. Biến thể đầu tiên không hoạt động khi tôi đã thử nó trong bash trên OSX jsut, nhưng phiên bản lớp nhân vật hoạt động:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Tony

@EugeneBiryukov xem nhận xét của tôi về bài đăng gốc
Tony

23

Theo đề xuất của Stéphane Chazelas trong câu trả lời được chấp nhận, giờ đây bạn có thể
tạo một tập lệnh /usr/local/bin/trim:

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

và cung cấp cho tập tin quyền thực thi:

chmod +x /usr/local/bin/trim

Bây giờ bạn có thể chuyển mọi đầu ra trimcho ví dụ:

cat file | trim

(đối với các ý kiến ​​dưới đây: tôi đã sử dụng điều này trước đây: while read i; do echo "$i"; done
cũng hoạt động tốt, nhưng ít hiệu quả hơn)


1
Chúc may mắn nếu tập tin của bạn rất lớn và / hoặc chứa dấu gạch chéo ngược.
don_crissti

1
@don_crissti: bạn có thể bình luận thêm một chút không?, giải pháp nào sẽ phù hợp hơn cho các tệp lớn và làm cách nào tôi có thể sửa đổi giải pháp của mình nếu tệp chứa dấu gạch chéo ngược?
rubo77

3
Bạn sẽ phải sử dụng while read -r lineđể bảo tồn những dấu xồ nguợc và thậm chí sau đó ... . Đối với các tập tin / tốc độ lớn, thực sự, bạn đã chọn giải pháp tồi tệ nhất. Tôi không nghĩ có gì tồi tệ hơn ngoài kia. Xem câu trả lời về Tại sao sử dụng vòng lặp shell để xử lý văn bản thực hành xấu? bao gồm cả nhận xét của tôi về câu trả lời cuối cùng trong đó tôi đã thêm một liên kết đến điểm chuẩn tốc độ. Các sedcâu trả lời ở đây là IMO hoàn toàn tốt và tốt hơn nhiều read.
don_crissti

@don_crissti ... và / hoặc có các dòng bắt đầu bằng -và theo sau là sự kết hợp của 1 hoặc nhiều ký tự e, E hoặc n và / hoặc chứa các ký tự NUL. Ngoài ra, một dòng không kết thúc sau dòng mới cuối cùng sẽ bị bỏ qua.
Stéphane Chazelas

1
Bạn cũng có thể thêm bí danh trong / etc / profile (hoặc ~ / .bashrc hoặc ~ / .zshrc, v.v.) bí danh trim = "awk '{\ $ 1 = \ $ 1}; 1'"
Jeff Clayton

22

xargs không có đối số làm điều đó.

Thí dụ:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

1
Điều này cũng hợp đồng nhiều không gian trong một dòng, không được yêu cầu trong câu hỏi
roaima

1
@roaima - đúng nhưng câu trả lời được chấp nhận cũng thu hẹp khoảng trắng (không được yêu cầu trong câu hỏi). Tôi nghĩ vấn đề thực sự ở đây là xargssẽ không cung cấp được nếu đầu vào chứa dấu gạch chéo ngược và dấu ngoặc đơn.
don_crissti

@don_crissti không có nghĩa là câu trả lời được chấp nhận trả lời đúng câu hỏi khi được hỏi. Nhưng trong trường hợp này, nó không được gắn cờ như một lời cảnh báo trong khi trong câu trả lời được chấp nhận. Tôi hy vọng đã làm nổi bật thực tế trong trường hợp nó có liên quan đến một độc giả tương lai.
roaima

Nó cũng phá vỡ trên dấu ngoặc đơn, dấu ngoặc kép, dấu gạch chéo ngược. Nó cũng chạy một hoặc nhiều echolời mời. Một số triển khai tiếng vang cũng sẽ xử lý các tùy chọn và / hoặc dấu gạch chéo ngược ... Điều đó cũng chỉ hoạt động đối với đầu vào một dòng.
Stéphane Chazelas

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

Nếu bạn đang đọc một dòng vào một biến shell, readthì điều đó đã được trừ khi được hướng dẫn khác .


1
+1 cho read. Vì vậy, nếu bạn chuyển sang đọc trong khi nó hoạt động:cat file | while read i; do echo $i; done
rubo77

1
@rubo ngoại trừ trong ví dụ của bạn, biến không được trích dẫn cũng được xử lý lại bởi trình bao. Sử dụng echo "$i"để xem tác dụng thực sự củaread
roaima

13

Nếu bạn lưu trữ các dòng dưới dạng các biến, bạn có thể sử dụng bash để thực hiện công việc:

xóa khoảng trắng hàng đầu khỏi chuỗi:

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

xóa khoảng trắng theo sau từ một chuỗi:

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

xóa tất cả khoảng trắng khỏi chuỗi:

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

Xóa tất cả khoảng trắng khỏi chuỗi không giống như xóa cả khoảng trắng ở đầu và cuối (như trong câu hỏi).
catpnosis

Giải pháp tốt nhất - nó chỉ yêu cầu bash dựng sẵn và không có nhánh quy trình bên ngoài.
dùng259412

2
Đẹp. Các tập lệnh chạy RẤT NHIỀU nếu chúng không phải kéo các chương trình bên ngoài (như awk hoặc sed). Điều này cũng hoạt động với các phiên bản "hiện đại" (93u +) của ksh.
dùng1683793

9

Để xóa tất cả các khoảng trắng ở đầu và cuối khỏi một đường nhất định nhờ vào công cụ 'đường ống', tôi có thể xác định 3 cách khác nhau không hoàn toàn tương đương. Những khác biệt này liên quan đến khoảng trắng giữa các từ của dòng đầu vào. Tùy thuộc vào hành vi dự kiến, bạn sẽ lựa chọn.

Ví dụ

Để giải thích sự khác biệt, hãy xem xét dòng đầu vào giả này:

"   \t  A   \tB\tC   \t  "

tr

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

trthực sự là một lệnh đơn giản Trong trường hợp này, nó xóa bất kỳ ký tự khoảng trắng hoặc bảng.

ôi

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

awk xóa các khoảng trắng đầu và đuôi và nén vào một khoảng trống mỗi khoảng trống giữa các từ.

quyến rũ

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

Trong trường hợp này, sedxóa các khoảng trắng ở đầu và đuôi mà không chạm vào bất kỳ khoảng trắng nào giữa các từ.

Ghi chú:

Trong trường hợp một từ trên mỗi dòng, trthực hiện công việc.


Không ai trong số này theo dõi / dẫn dòng mới mặc dù
xứ cao cấp

+1 cho danh sách các giải pháp với đầu ra (đôi khi không mong muốn) của chúng.
Tony

@ user61382 này khá muộn, nhưng hãy xem nhận xét của tôi về bài viết gốc.
Tony

@highmaintenance: sử dụng [:space:], thay vì [: blank:], cho lệnh tr, như : ... | tr -d [:space:], để xóa dòng mới quá. (xem man tr:)
tron5

6

sed là một công cụ tuyệt vời cho điều đó:

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

Bạn có thể sử dụng nó cho trường hợp của bạn hoặc là đường ống trong văn bản, ví dụ

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

hoặc bằng cách hành động trên 'nội tuyến' nếu bạn sedlà GNU:

sed -i 's/...' file

nhưng thay đổi nguồn theo cách này là "nguy hiểm" vì nó có thể không phục hồi được khi nó không hoạt động đúng (hoặc ngay cả khi nó hoạt động!), vì vậy hãy sao lưu trước (hoặc sử dụng -i.bakcũng có lợi cho một số BSD sed) !


2

dịch lệnh sẽ làm việc

cat file | tr -d [:blank:]

4
Lệnh này không đúng vì nó loại bỏ tất cả các khoảng trắng khỏi tệp, không chỉ khoảng trắng hàng đầu / dấu.
Brian Redbeard

@BrianRedbeard Bạn đúng. Đây vẫn là một câu trả lời hữu ích cho một chuỗi nguyên khối, không có khoảng trắng.
Anthony Rutledge

0

Nếu chuỗi một đang cố gắng cắt ngắn và liên tục / liền kề, người ta có thể chỉ cần chuyển nó dưới dạng tham số cho bất kỳ hàm bash nào:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.