Yalnızca 'tr' kullanarak bir boşluk ile birden çok alanı değiştirin


71

Bir dosyam var f1.txt:

ID     Name
1      a
2         b
3   g
6            f

Boşluk sayısı sabit değil . Tüm beyaz alanları tek bir boşlukla değiştirmenin en iyi yolu nedir tr?

Şu ana kadar sahip olduğum şey bu:

cat f1.txt | tr -d " "

Ancak çıktı:

IDName
1a
2b
3g
6f

Ama şöyle görünmesini istiyorum:

ID Name
1 a
2 b
3 g
6 f

Lütfen dene ve kaçın sed.


6
Sed önlemek için neden bu kadar önemlidir? Ne işe yarıyorsa onu kullan!
David Richerby

7
Çünkü nasıl yapıldığını biliyorum sed. Başka yollarla bilmek istedi
:)

Yanıtlar:


106

Ile tr, squeeze yineleme seçeneğini kullanın:

$ tr -s " " < file
ID Name
1 a
2 b
3 g
6 f

Veya bir awkçözüm kullanabilirsiniz :

$ awk '{$2=$2};1' file
ID Name
1 a
2 b
3 g
6 f

Kayıttaki bir alanı değiştirdiğinizde, awkyeniden oluşturun $0, tüm alanı alır ve bunları OFSvarsayılan olarak bir alan olan birbiriyle birleştirerek birleştirir .

Bu, boşluk ve sekmelerin (ve yerel ayarlara ve uygulamasına bağlı olarak muhtemelen diğer boş karakterlerin) dizilerini tek bir alana sıkıştıracak awk, ancak aynı zamanda her satırın önündeki ve sondaki boşlukları kaldıracaktır.


1
Bu da harika bir çözüm. . . Şimdi hangisini seçeceğimi bilmiyorum: / @Gnouc
gkmohit

İstediğiniz herhangi bir çözümü seçmekten çekinmeyin ve sizin için çalışır. Çözümümün @ polym'in cevabından farklı olduğuna dikkat edin.
cuonglm

1
:)) yuppi! @Gnouc un cevabı gerçekten dinamiktir, çünkü kullanır awk, her şeyi yapabilir. Onun çözümünü de kabul edebilirsiniz. Tek bir şey: Gnouc muhtemelen emrinizde awk formatının ne yaptığını açıklayabilir misiniz? Ayrıca çıktının Unknown'ın beklenen çıktısına uygun olması için sekmeler / boşluklar ekleyebilir misiniz?
polim

1
@polym: Bilinmeyen'in son düzenlemesiyle çıktı gibi değil, sadece bir boşluk istiyor gibi görünüyor column -t. İçin açıklama ekle awk.
cuonglm

4
Burada küçük bir fark var. trBir satırın sonundaki iki boşluğu tek boşlukla değiştirir. awktüm sondaki boşlukları kaldıracak.
Anne van Rossum

19

Sadece kullan column:

column -t inputFile

Çıktı:

ID  Name
1   a
2   b
3   g
6   f

Wonderful and a quick reply :)
gkmohit

1
@Bilinmeyen Hizmette olmak harika :)!
polym

1
@Gnouc vay cool, sütun da argüman olarak bir dosya alır. güzel, teşekkürler!
polym

İkinci sütunu ancak istersem nasıl alabilirim? Denedim column -t f1.txt | cut -d " " -f2 Ama beklediğim bir çözüm değildi
gkmohit

2
Awk kullandıktan sonra: column -t file | awk '{print $2}'yalnızca ikinci sütunu yazdırır
polym

8

Eğer "boşluk" sıkmak istiyorsanız, tr'in önceden tanımlanmış karakter kümelerini ": blank:" (yatay boşluk sekmesi ve boşluk) veya ": boşluk:" (dikey boşluk):

/bin/echo -e  "val1\t\tval2   val3" | tr -s "[:blank:]"

Örnekler Red Hat 5 (GNU tr) üzerinde yapıldı.

Benim durumumda, tüm boşlukları tek bir alana normalleştirmek istedim, böylece uzaya bir verici olarak güvenebilecektim.

Dastrobu'nun ikinci yorumunda belirtildiği gibi, man sayfasındaki ifadeleri kaçırdım:

 -s uses the last specified SET, and occurs after translation or deletion.

Bu, ilk tr'i ortadan kaldırmamızı sağlar. Kudo, dürüstlüğüm karşısında sabrını araştırdı.

Daha önce Redis config'den port ayrıştırma. dosya:

grep "^port" $redisconf | tr "[:blank:]" " " | tr -s "[:blank:]"  | cut -d" " -f2

Ardından SET2 sıkma ile belirtilmiş olarak:

grep "^port" $redisconf | tr -s "[:blank:]" " " | cut -d" " -f2

Çıktı:

6379

Boşluk nüanslarını kapsayan daha fazla ayrıntı için

[: Blank:] karakter sınıfına giren art arda gelen karışık karakterler söz konusu olduğunda, sıkmanın nerede başarısız olduğunu gösterin:

 /usr/bin/printf '%s \t %s' id myname | tr -s "[:blank:]"  | od -cb
0000000   i   d      \t       m   y   n   a   m   e
        151 144 040 011 040 155 171 156 141 155 145
0000013

Not: Printf formatındaki iki string alanım 1 boşluk, 1 sekme ve 1 boşluk ile ayrılır. Sıkıştırmadan sonra bu dizi hala var. Octal dökümü çıktısında bu, 040 011 040 ascii dizisi ile temsil edilir.


1
Gerçekten ihtiyacın var tr "[:blank:]" " " | tr -s "[:blank:]"mı? Sanırım ilk bölüm yeterli olacak, yani tr "[:blank:]" " "boşlukları normalleştirdiği ve yerini değiştirdiği için. Man sayfasından: "Karakterlerin çoklu oluşumlarını sıkıştır [...] Bu tüm silme ve çeviri tamamlandıktan sonra gerçekleşir."
dastrobu

2
öyleyse ´tr -s "[: blank:]" "" ´, önce tüm boşlukları çevirir ve sonra boşlukları sıkar. Bir saniye için gerek yok.
dastrobu

1
printf 'ID \t Name\n' | tr -s "[:blank:]" " " | od -cb(@Dastrobu tarafından önerildiği gibi) denedim ve çıktı olarak ID Name\n( bir boşlukla) aldım . Aslında denediniz mi, @ user3183018?
Scott

1
Tamam, bunu tekrar söylemeye çalışayım. Bir alanı temsil eden printf 'ID␣\t␣Name\n' | tr -s "[:blank:]" "␣"  (@dastrobu tarafından önerildiği gibi) yaptım ve ID␣Name\nçıktı olarak (bir boşlukla) aldım . Bu, soruyu başlık dizgilerini kullanmam dışında, “Port <SPACE> <TAB> <SPACE> 6379” örneğinizle tamamen aynı . Denedin mi tr -s "[:blank:]"(son "␣"tartışma olmadan ) merak ediyorum  .
Scott

1
Yaptığımda printf 'ID \t Name\n' | od -cb, tam olarak ne olması gerektiğini gösteriyor: ID ⁠  \t ⁠  N a m e \n(yani  ID 040 011 040 N a m e\n). Bu arada, kendi kanıtınıza göre, tam olarak tahmin ettiğim hatayı yapıyorsunuz: @dastrobu ve benim şimdi dört kez sunduğumuz komut yerine , koşuyorsunuz tr -s "[:blank:]"(yani,  trbir seçenek ve  bir argümanla) tr -s '[:blank:]' '␣'(yani,  trbir seçenek ve  iki argümanla ).
Scott,

5

Kim bir programa ihtiyaç duyar (kabuk hariç)?

while read a b
do
    echo "$a $b"
done < f1.txt

Polimerin cevabında olduğu gibi, ikinci sütundaki değerlerin aynı hizada olmasını istiyorsanız, yerine şunu columnkullanın :printfecho

while read a b
do
    printf '%-2s %s\n' "$a" "$b"
done < f1.txt

1
İlk olarak, tr - ile karşılaştırıldığında, girdi çok küçük olmadıkça, bu oldukça zayıf bir öneridir - girişimin çok küçük bir ağırlığından daha ağır basmadığı sürece tr- bu ne kadar çok iş yazacağını söylemez. Son olarak, bu yazının sorulan soruyu aslında cevaplamadığını söylemez misiniz? Yalnızca tr kullanarak tüm beyaz boşlukları tek boşlukla değiştirmenin en iyi yolu nedir?
mikeserv

1
Ve ayrıca - daha kolay bir şey yapamaz $IFSmısın? Belki ister: IFS=' <tab>' set -f ; echo $(cat <file)?
mikeserv

2

Bu eski bir soru ve birçok kez çözüldü. Sadece bütünlük için: Ben bir benzetme sorunu yaşadım, ancak boru aracılığıyla hatları başka bir programa geçirmek istedim. Xargs kullandım .

-L max-lines
   Use at most max-lines nonblank input lines per command line.
   Trailing blanks cause an input line to be logically continued 
   on the next input line.  Implies -x.

böylece cat f1.txt | xargs -L1tam olarak ne istediğini çıktı gibi görünüyor.

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.