Önde gelen ve sondaki boşlukları bir çıktının her satırından nasıl kesebilirim?


155

Bir çıktıdaki her satırdaki tüm önde gelen ve sondaki boşlukları ve sekmeleri kaldırmak istiyorum.

trimÇıktımı içine çekebileceğim basit bir araç var mı ?

Örnek dosya:

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
Burada yeni hatları kaldırmak için bir çözüm arayanlar için bu farklı bir sorundur. Tanım olarak, yeni bir satır yeni bir metin satırı oluşturur. Bu nedenle, bir metin satırı yeni satır içeremez. Sormak istediğiniz soru, bir dizgenin başından veya sonundan yeni bir satırın nasıl kaldırılacağı: stackoverflow.com/questions/369758 veya sadece boşluk içeren boş satırların veya satırların nasıl kaldırılacağıdır: serverfault.com/questions/252921
Tony

Yanıtlar:


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

veya daha kısa:

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

Baştaki ve sondaki boşluk veya sekme karakterlerini 1 keser ve ayrıca sekme ve boşluk dizilerini tek bir alana sıkar.

Bu işe yarar çünkü alanlardan birine bir şey atadığınızda , tüm alanları ( , ..., ) ile (varsayılan olarak boşluk ) birleştirerek tüm awkkaydı (basıldığı gibi ) yeniden oluşturur.print$1$NFOFS

1 (ve yerel ve awkuygulamaya bağlı olarak büyük olasılıkla diğer boş karakterler )


2
İkinci örnekte noktalı virgül gereksizdir. Kullanılabilir:awk '{$1=$1}1'
Brian


İlginç ... Hiçbir noktalı virgül gawk, mawk ve OS X'in awk'si tarafından desteklenmez. (En azından sürümlerim için (sırasıyla 1.2, 4.1.1 ve 20070501)
Brian

1
Bu yaklaşımdan hoşlanmadığım tek şey, çizginin içindeki tekrar eden boşlukları kaybetmeniz. Örneğin,echo -e 'foo \t bar' | awk '{$1=$1};1'
user.friendly

2
echo ' hello ' | xargs
JREAM,

44

GNU kullanıyorsanız, komut bu şekilde yoğunlaştırılabilir sed:

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

Örnek

İşte eylemde yukarıdaki komutu var.

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

Komutun istenen karakterleri doğru şekilde hexdumpçıkardığını onaylamak için kullanabilirsiniz 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

Karakter sınıfları

Ayrıca, kümeleri tam anlamıyla şöyle sıralamak yerine karakter sınıfı adlarını kullanabilirsiniz [ \t]:

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

Örnek

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

Normal ifadelerden (regex) yararlanan GNU araçlarının çoğu bu sınıfları desteklemektedir.

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

Bunları değişmez kümeler yerine kullanmak her zaman bir alan israfı gibi görünür, ancak kodunuzun taşınabilir olması veya alternatif karakter kümeleriyle ilgilenmeniz gerekiyorsa (uluslararası düşünün), muhtemelen sınıf adlarını kullanmak isteyeceksiniz yerine.

Referanslar


Bunun genel durumla (unicode, vb.) [[:space:]]Eşdeğer olmadığını unutmayın [ \t]. [[:space:]]Muhtemelen çok daha yavaş olacaktır (unicode'da diğerlerinden çok daha fazla beyaz boşluk türü olduğu için ' 've daha '\t'). Diğerleri için aynı şey.
Olivier Dulac

sed 's/^[ \t]*//'taşınabilir değil. Hatta POSIX bile bir boşluk, ters eğik çizgi veya tkarakter sırasının kaldırılmasını gerektiriyor ve GNU sedda POSIXLY_CORRECTçevrede olduğu zaman bunu yapıyor .
Stéphane Chazelas

Newlines karakterlerini kırpmak istersem ne olur? '\ n \ n metin \ n \ n'
Eugene Biryukov

Aw çözümünde olduğu gibi diğer yan etkilerin olmamasından dolayı sed çözümünü seviyorum. İlk varyasyon şimdi OSX jsut'ta bash olarak denediğimde çalışmaz, ancak karakter sınıfı versiyonu işe yarıyor:sed 's/^[[:blank:]]*//;s/[[:blank:]]*$//'
Tony

@EugeneBiryukov orijinal yazıdaki yorumumu görüyor
Tony

23

Stéphane Chazelas tarafından kabul edilen cevapta önerildiği gibi , artık
bir senaryo oluşturabilirsiniz /usr/local/bin/trim:

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

ve bu dosya çalıştırılabilir haklarını verin:

chmod +x /usr/local/bin/trim

Artık her çıktıyı trimörneğin şuna aktarabilirsiniz :

cat file | trim

(aşağıdaki yorumlar için: bunu daha önce kullandım: while read i; do echo "$i"; done
bu da iyi çalışıyor ancak daha az performans gösteriyor)


1
Dosyanız büyükse ve / veya ters eğik çizgi varsa, iyi şanslar.
don_crissti

1
@ don_crissti: biraz daha yorum yapabilir misiniz ?, hangi dosyalar büyük dosyalar için daha uygun olurdu ve dosya ters eğik çizgiler içeriyorsa çözümümü nasıl değiştirebilirim?
rubo77

3
Sen kullanmak gerekecektir while read -r lineters eğik çizgi ve korumak için ... o zaman bile . Büyük dosyalar / hız olarak, gerçekten, en kötü çözümü seçtiniz. Orada daha kötü bir şey olduğunu sanmıyorum. Metni kötü uygulama işlemek için neden bir kabuk döngü kullanıyor? hız ölçütüne bir link eklediğim son cevap hakkındaki yorumum dahil. Buradaki sedcevaplar tamamen iyi IMO ve çok daha iyi read.
don_crissti

@ don_crissti ... ve / veya -1 veya daha fazla e, E veya n karakteriyle başlayan ve ardından gelen ve / veya NUL karakterleri içeren çizgiler var . Ayrıca, son satırdan sonra sonlandırılmayan bir satır atlanacaktır.
Stéphane Chazelas

1
Ayrıca / etc / profile (veya ~ / .bashrc veya ~ / .zshrc etc ...) içine bir takma ad ekleyebilirsiniz. Alias ​​trim = "awk '{\ $ 1 = \ $ 1}; 1'"
Jeff Clayton

22

Argümanlar olmadan xargs bunu yapar.

Örnek:

trimmed_string=$(echo "no_trimmed_string" | xargs) 

1
Bu, aynı zamanda, bir soru
dahilinde sorulmamış

1
@roaima - true ancak kabul edilen cevap, (soruda istenmeyen) alanları da sıkar. Bence asıl sorun xargs, girdi ters eğik çizgi ve tek tırnak içeriyorsa , bunu yapmanın başarısız olacağını düşünüyorum .
don_crissti 9:15

@don_crissti, bu kabul edilen cevabın sorulan gibi soruyu doğru cevapladığı anlamına gelmez. Ancak bu durumda burada bir uyarı olarak işaretlenmedi, oysa kabul edilen cevapta öyleydi. Gelecekteki bir okurla ilgisi olması ihtimalini vurguladım.
roaima

Ayrıca, tek tırnak üzerinde çift tırnak, ters eğik çizgi karakterleri kırar. Aynı zamanda bir veya daha fazla echoçağrı yürütür . Bazı yankı uygulamaları, seçenekleri ve / veya ters eğik çizgileri de işleyecektir ... Bu sadece tek satırlık giriş için de geçerlidir.
Stéphane Chazelas

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

Bir kabuk değişkenine bir satır okuyorsanız, aksi belirtilmediği sürece , readbunu zaten yapar .


1
İçin +1 read. Öyleyse, okurken boruya çalışırsanız:cat file | while read i; do echo $i; done
rubo77, 21:13

1
@ rubo, örneğin, örneklenmemiş değişkenin kabuk tarafından da yeniden işlenmesi dışında. Kullanım echo "$i"gerçek etkisini görmek içinread
roaima

13

Satırları değişken olarak saklarsanız, işi yapmak için bash kullanabilirsiniz:

önde gelen boşlukları bir dizeden kaldırmak:

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

izleyen boşlukları bir dizeden kaldır:

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

bir dizedeki tüm boşlukları siler:

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

Tüm beyaz boşlukları bir dizgeden çıkarmak, hem baştaki hem de sondaki boşlukları kaldırmakla aynı şey değildir (söz konusu olduğu gibi).
kataloz

En iyi çözüm - yalnızca bash yerleşikleri gerektirir ve harici işlem çatalları gerektirmez.
user259412

2
Güzel. Dıştaki programları (awk veya sed gibi) çekmek zorunda kalmazlarsa, komut dosyaları LOT'u daha hızlı çalıştırır. Bu, ksh'ın "modern" (93u +) sürümleriyle de çalışır.
user1683793

9

'Borulu' bir takım sayesinde tüm öndeki ve sondaki boşlukları belirli bir hattan çıkarmak için, tamamen eşdeğer olmayan 3 farklı yol tanımlayabilirim. Bu farklılıklar giriş satırındaki kelimeler arasındaki boşlukları ilgilendirir. Beklenen davranışa bağlı olarak, seçiminizi yaparsınız.

Örnekler

Farkları açıklamak için, bu sahte giriş satırını göz önünde bulunduralım:

"   \t  A   \tB\tC   \t  "

tr

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

trgerçekten basit bir komuttur. Bu durumda, herhangi bir boşluk veya tablo karakterini siler.

awk

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

awk önde gelen ve arkadaki boşlukları siler ve kelimeler arasındaki her boşluğu tek bir boşluğa sıkar.

sed

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

Bu durumda, sedkelimeler arasındaki boşluklara dokunmadan önde gelen ve kuyruktaki boşlukları siler.

Not:

Satır başına bir kelime olması durumunda tr, işi yapar.



(Bazen beklenmeyen) çıkışlı çözümlerin listesi için +1.
Tony,

@ user61382 Bu oldukça geç, ancak orijinal yayına yorumumu bakın.
Tony,

@highmaintenance: kullanım [:space:]yerine [: blank:], komut için tr, gibi: ... | tr -d [:space:]çok yeni satır kaldırın. (bkz: man tr)
tron5

6

sed bunun için harika bir araçtır:

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

Davanız için kullanabilirsiniz, örneğin metinde boru olması

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

ya sedda GNU olanıysanız, 'satır içi' üzerine bakarak :

sed -i 's/...' file

ancak kaynağı bu şekilde değiştirmek "tehlikelidir", çünkü doğru çalışmadığında (ya da çalıştığında bile) kurtarılamaz olabilir, bu nedenle ilk önce yedekleyin (ya -i.bakda bazı BSD'ler için taşınabilir olma avantajına sahip olan kullanın sed) !


2

çeviri komutu işe yarayacak

cat file | tr -d [:blank:]

4
Bu komut yalnızca boşluklardan / izleyen boşluklardan değil, dosyadaki tüm boşlukları kaldırdığından doğru değildir.
Brian Redbeard

@BrianRedbeard Haklısın. Bu, boşluksuz, monolitik bir dize için hala yararlı bir cevaptır.
Anthony Rutledge

0

Eğer bir dize kırpmaya çalışıyorsa kısa ve sürekli / bitişikse, basitçe herhangi bir bash işlevine parametre olarak geçirilebilir:

    trim(){
        echo $@
    }

    a="     some random string   "

    echo ">>`trim $a`<<"
Output
>>some random string<<
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.