Bagaimana cara memotong spasi putih memimpin dan tertinggal dari setiap baris beberapa output?

155

Saya ingin menghapus semua spasi dan tab depan dan belakang dari setiap baris dalam output.

Apakah ada alat sederhana seperti trimsaya dapat menyalurkan output saya ke?

File contoh:

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 
rubo77
sumber
1
Bagi siapa pun yang mencari solusi untuk menghapus baris baru di sini, itu adalah masalah yang berbeda. Menurut definisi, baris baru membuat baris teks baru. Oleh karena itu satu baris teks tidak dapat berisi baris baru. Pertanyaan yang ingin Anda tanyakan adalah bagaimana menghapus baris baru dari awal atau akhir string: stackoverflow.com/questions/369758 , atau bagaimana menghapus garis kosong atau garis yang hanya spasi putih: serverfault.com/questions/252921
Tony

Jawaban:

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

atau lebih pendek:

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

Akan memangkas spasi awal dan akhir karakter tab 1 dan juga memeras urutan tab dan spasi menjadi satu ruang.

Itu bekerja karena ketika Anda menetapkan sesuatu ke salah satu bidang , awkmembangun kembali seluruh catatan (seperti yang dicetak oleh print) dengan bergabung dengan semua bidang ( $1, ..., $NF) dengan OFS(ruang pada pengaturan standar).

1 (dan mungkin karakter kosong lainnya tergantung pada lokal dan awkimplementasinya)

Stéphane Chazelas
sumber
2
Titik koma pada contoh kedua tidak berguna. Bisa menggunakan:awk '{$1=$1}1'
Brian
8
@ Brian, tidak, ;ini diperlukan dalam sintaks awk standar
Stéphane Chazelas
Menarik ... Tidak ada titik koma yang didukung oleh gawk, mawk dan OS X's awk. (Setidaknya untuk versi saya (1.2, 4.1.1, dan 20070501, masing-masing)
Brian
1
Satu-satunya hal yang saya tidak suka tentang pendekatan ini adalah bahwa Anda kehilangan ruang berulang dalam garis. Misalnya,echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly
2
echo ' hello ' | xargs
JREAM
44

Perintah dapat diringkas seperti itu jika Anda menggunakan GNU sed:

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

Contoh

Inilah perintah di atas dalam aksi.

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

Anda dapat menggunakan hexdumpuntuk mengonfirmasi bahwa sedperintah tersebut menghapus karakter yang diinginkan dengan benar.

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

Kelas karakter

Anda juga dapat menggunakan nama kelas karakter alih-alih mendaftar secara himpunan set seperti ini [ \t],:

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

Contoh

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

Sebagian besar alat GNU yang menggunakan ekspresi reguler (regex) mendukung kelas-kelas ini.

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

Menggunakan ini alih-alih set literal selalu tampak seperti buang-buang ruang, tetapi jika Anda khawatir dengan kode Anda yang portabel, atau harus berurusan dengan set karakter alternatif (pikirkan internasional), maka Anda mungkin ingin menggunakan nama kelas sebagai gantinya.

Referensi

slm
sumber
Catatan yang [[:space:]]tidak setara dengan [ \t]dalam kasus umum (unicode, dll). [[:space:]]mungkin akan jauh lebih lambat (karena ada lebih banyak jenis spasi putih di unicode daripada adil ' 'dan '\t'). Hal yang sama untuk yang lainnya.
Olivier Dulac
sed 's/^[ \t]*//'tidak portabel. Pada dasarnya POSIX bahkan mengharuskan untuk menghapus urutan ruang, garis miring terbalik atau tkarakter, dan itulah yang dilakukan GNU sedketika POSIXLY_CORRECTberada di lingkungan.
Stéphane Chazelas
Bagaimana jika saya ingin memotong karakter baris baru? '\ n \ n teks \ n \ n'
Eugene Biryukov
Saya suka solusi sed karena kurangnya efek samping lain seperti pada solusi awk. Variasi pertama tidak berfungsi ketika saya mencobanya di bash di OSX hanya sekarang, tetapi versi kelas karakter tidak berfungsi:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Tony
@EugeneBiryukov melihat komentar saya pada posting asli
Tony
23

Seperti yang disarankan oleh Stéphane Chazelas dalam jawaban yang diterima, Anda sekarang dapat
membuat skrip /usr/local/bin/trim:

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

dan berikan file itu hak yang dapat dieksekusi:

chmod +x /usr/local/bin/trim

Sekarang Anda dapat meneruskan setiap output ke trimmisalnya:

cat file | trim

(untuk komentar di bawah ini: saya menggunakan ini sebelumnya: while read i; do echo "$i"; done
yang juga berfungsi dengan baik, tetapi kurang performan)

rubo77
sumber
1
Semoga berhasil jika file Anda besar dan / atau mengandung garis miring terbalik.
don_crissti
1
@don_crissti: dapatkah Anda berkomentar lebih banyak ?, solusi mana yang lebih cocok untuk file besar, dan bagaimana saya bisa memodifikasi solusi saya jika file mengandung backslash?
rubo77
3
Anda harus menggunakan while read -r lineuntuk melestarikan backslashes dan bahkan kemudian ... . Mengenai file / kecepatan besar, sungguh, Anda memilih solusi terburuk. Saya tidak berpikir ada yang lebih buruk di luar sana. Lihat jawaban pada Mengapa menggunakan shell loop untuk memproses teks praktik buruk? termasuk komentar saya pada jawaban terakhir tempat saya menambahkan tautan ke tolok ukur kecepatan. The sedjawaban di sini adalah baik-baik saja IMO dan jauh lebih baik daripada read.
don_crissti
@don_crissti ... dan / atau memiliki garis yang dimulai dengan -dan diikuti oleh kombinasi 1 atau lebih e, E atau n karakter, dan / atau berisi karakter NUL. Selain itu, baris yang tidak diakhiri setelah baris baru terakhir akan dilewati.
Stéphane Chazelas
1
Anda juga dapat menambahkan alias di / etc / profile (atau ~ / .bashrc atau ~ / .zshrc dll ...) alias trim = "awk '{\ $ 1 = \ $ 1}; 1'"
Jeff Clayton
22

xargs tanpa argumen melakukannya.

Contoh:

trimmed_string=$(echo "no_trimmed_string" | xargs) 
Newton_Jose
sumber
1
Ini juga mengontrak banyak ruang dalam satu garis, yang tidak diminta dalam pertanyaan
roaima
1
@roaima - benar tetapi jawaban yang diterima juga meremas spasi (yang tidak diminta dalam pertanyaan). Saya pikir masalah sebenarnya di sini adalah bahwa xargsakan gagal memberikan jika input berisi garis miring terbalik dan tanda kutip tunggal.
don_crissti
@don_crissti itu tidak berarti jawaban yang diterima dengan benar menjawab pertanyaan yang ditanyakan. Tetapi dalam kasus ini di sini itu tidak ditandai sebagai peringatan sedangkan dalam jawaban yang diterima itu. Mudah-mudahan saya telah menyoroti fakta kalau-kalau itu relevan bagi pembaca di masa depan.
roaima
Itu juga istirahat pada tanda kutip tunggal, tanda kutip ganda, karakter backslash. Itu juga menjalankan satu atau lebih echodoa. Beberapa implementasi gema juga akan memproses opsi dan / atau garis miring terbalik ... Itu juga hanya berfungsi untuk input baris tunggal.
Stéphane Chazelas
17
sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'

Jika Anda membaca baris ke variabel shell, readlakukan itu kecuali diinstruksikan sebaliknya .

Gilles
sumber
1
+1 untuk read. Jadi, jika Anda pipa sambil membacanya berfungsi:cat file | while read i; do echo $i; done
rubo77
1
@rubo kecuali bahwa dalam contoh Anda, variabel yang tidak dikutip juga diproses ulang oleh shell. Gunakan echo "$i"untuk melihat efek sebenarnya dariread
roaima
13

Jika Anda menyimpan baris sebagai variabel, Anda dapat menggunakan bash untuk melakukan pekerjaan:

hapus spasi putih terkemuka dari string:

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

hapus spasi kosong dari string:

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

hapus semua spasi putih dari string:

echo ${text//[[:space:]]}
Łukasz Rajchel
sumber
Menghapus semua spasi putih dari string tidak sama dengan menghapus spasi spasi awal dan akhir (seperti yang dipermasalahkan).
catpnosis
Sejauh ini solusi terbaik - hanya membutuhkan bash builtin dan tidak ada proses eksternal.
user259412
2
Bagus. Script menjalankan BANYAK lebih cepat jika mereka tidak harus menarik program luar (seperti awk atau sed). Ini bekerja dengan versi "modern" (93u +) dari ksh, juga.
user1683793
9

Untuk menghapus semua spasi awal dan akhir dari garis tertentu berkat alat 'pipa', saya dapat mengidentifikasi 3 cara berbeda yang tidak sepenuhnya sama. Perbedaan-perbedaan ini menyangkut ruang antara kata-kata dari garis input. Bergantung pada perilaku yang diharapkan, Anda akan menentukan pilihan.

Contohnya

Untuk menjelaskan perbedaannya, mari pertimbangkan jalur input dummy ini:

"   \t  A   \tB\tC   \t  "

tr

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

trbenar-benar perintah sederhana. Dalam hal ini, ia menghapus spasi atau karakter tabulasi.

awk

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

awk menghapus spasi terdepan dan tailing dan menekan ke satu spasi setiap spasi di antara kata-kata.

sed

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

Dalam hal ini, sedhapus spasi di depan dan di belakang tanpa menyentuh spasi di antara kata-kata.

Ucapan:

Dalam hal satu kata per baris, trlakukan pekerjaan.

frozar
sumber
Tak satu pun dari ini trims mengikuti / memimpin baris baru
pemeliharaan tinggi
+1 untuk daftar solusi dengan outputnya (terkadang tidak terduga).
Tony
@ user61382 ini agak terlambat, tetapi lihat komentar saya di posting asli.
Tony
@ pemeliharaan tinggi: gunakan [:space:], alih-alih [: kosong:], untuk perintah tr, seperti :, ... | tr -d [:space:]untuk menghapus baris baru juga. (lihat: man tr)
tron5
6

sed adalah alat yang bagus untuk itu:

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

Anda dapat menggunakannya untuk kasing Anda baik dalam teks, mis

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

atau dengan bertindak sesuai 'inline' jika Anda sedadalah GNU:

sed -i 's/...' file

tetapi mengubah sumber dengan cara ini "berbahaya" karena mungkin tidak dapat dipulihkan ketika tidak berfungsi dengan benar (atau bahkan ketika itu benar!), jadi backup terlebih dahulu (atau gunakan -i.bakyang juga memiliki manfaat menjadi portabel untuk beberapa BSD sed) !

Michael Durrant
sumber
2

Perintah menerjemahkan akan bekerja

cat file | tr -d [:blank:]
Srinagesh
sumber
4
Perintah ini tidak benar karena menghapus semua spasi dari file, tidak hanya memimpin / mengekstrak spasi.
Brian Redbeard
@BrianRedbeard Anda benar. Ini masih merupakan jawaban yang berguna untuk string monolitik, tanpa spasi.
Anthony Rutledge
0

Jika string yang hendak dipotong pendek dan kontinu / berdekatan, seseorang dapat dengan mudah memberikannya sebagai parameter untuk fungsi bash:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
Subrata Das
sumber