Bir metin dosyasında sadece ilk sütunu ve son sütunu göstermek için bir kabuk komutu nasıl kullanılır?


30

Bir metin dosyasında yalnızca ilk sütunu ve son sütunu göstermek için sed komutunun nasıl kullanılacağını bulmak için biraz yardıma ihtiyacım var. Sütun 1 için şu ana kadar sahip olduğum şey:

cat logfile | sed 's/\|/ /'|awk '{print $1}'

Benim de göstereceğim son sütunu almaya çalışırken zayıflığım şuydu:

cat logfile | sed 's/\|/ /'|awk '{print $1}{print $8}'

Ancak bu ilk sütunu ve son sütunu alır ve bunları bir listede birleştirir. İlk sütunu ve son sütunları sed ve awk komutlarıyla açıkça yazdırmanın bir yolu var mı?

Örnek giriş:

foo|dog|cat|mouse|lion|ox|tiger|bar

5
Lütfen bir miktar numune girişi sağlayın.
jasonwryan

Yanıtlar:


51

Neredeyse. Her iki sütun referansını da yan yana koyun.

cat logfile | sed 's/|/ /' | awk '{print $1, $8}'

Ayrıca catburada ihtiyacınız olmadığını unutmayın .

sed 's/|/ /' logfile | awk '{print $1, $8}'

Ayrıca awk, sütun ayırıcıların |boşluklar yerine olduğunu söyleyebilirsiniz , bu yüzden sedikisine de gerek yoktur .

awk -F '|' '{print $1, $8}' logfile

Gereğince önerileri ile Caleb , hala tam olarak sekiz orada olmasa bile, son alanı çıktılar bir çözüm istiyorsanız, kullanabileceğiniz $NF.

awk -F '|' '{print $1, $NF}' logfile

Ayrıca, çıktının |ayırıcıları tutmasını istiyorsanız, boşluk kullanmak yerine, çıktı alanı ayırıcılarını belirleyebilirsiniz. Ne yazık ki, sadece -Fbayrak kullanmaktan biraz sakar , fakat işte üç yaklaşım.

  • Giriş ve çıkış alanı ayırıcılarını awkBEGIN bloğunda kendi içinde atayabilirsiniz .

    awk 'BEGIN {FS = OFS = "|"} {print $1, $8}' logfile
  • Bu değişkenleri awkkomut satırından, -vbayrak üzerinden çağırırken atayabilirsiniz .

    awk -v 'FS=|' -v 'OFS=|' '{print $1, $8}' logfile
  • ya da sadece:

    awk -F '|' '{print $1 "|" $8}' logfile

4
İyi bir iş bu sorunun nasıl basitleştirilebileceğini göstermektedir. |Dize bitiştirme için varsayılan alan yerine çıktı ayırıcı olarak nasıl kullanılacağı hakkında bir not ekleyebilirsiniz . Ayrıca son sütunu almak için $NFsabit kodlama yerine kullanmayı açıklayabilirsiniz $8.
Caleb

12

Sadece ilk baştan sona |bir |(veya tercih ederseniz) ile değiştirin:

sed 's/|.*|/|/'

Özel olan herhangi bir seduygulama olmamasına rağmen |(uzun süreli düzenli ifadeler yoluyla -Eveya -rbazı uygulamalarda etkinleştirilmediği sürece ), \|kendisinin GNU gibi bazılarında özel olduğunu unutmayın sed. Yani gerektiğini değil kaçmak |eşleşmesini bunu düşünüyorsanız |karakter.

Boşluk ile değiştiriliyorsa ve giriş zaten yalnızca bir tane içeren satırlar içeriyorsa , bunlarla eşleşmeyecek |şekilde özel olarak davranmanız gerekir |.*|. Olabilirdi:

sed 's/|\(.*|\)\{0,1\}/ /'

(bu .*|kısmı isteğe bağlı yapar) Veya:

sed 's/|.*|/ /;s/|/ /'

veya:

sed 's/\([^|]*\).*|/\1 /'

Girdideki alanların sayısına bakılmaksızın birinci ve sekizinci alanları istiyorsanız, o zaman sadece:

cut -d'|' -f1,8


(tüm bunlar girişin geçerli metin oluşturduğunu varsayarak herhangi bir POSIX uyumlu yardımcı programla çalışacaktı (özellikle, sedgiriş, örneğin şu anda olduğu gibi geçerli yerel ayarda geçerli karakterler oluşturmayan bayt dizileri veya bayt dizileri varsa işe yaramaz printf 'unix|St\351phane|Chazelas\n' | sed 's/|.*|/|/'. bir UTF-8 yerel ayarı)).


11

awkYine de kullanıyorsunuz :

awk '{ print $1, $NF }' file

2
Giriş alanı ayırıcısını belirtmeniz gerekmez mi (bu durumda bunun |yerine boşluk gibi görünüyor ) -F\|? Ayrıca çıktı için aynı sınırlayıcıyı kullanmak isterse?
Caleb

@Caleb Muhtemelen: OP'nin çalışmayan örneklere dayanarak tahmin etmeye çalışmak yerine girdilerin tam olarak nasıl göründüğünü onaylamasını bekliyordum ...
jasonwryan

1
Girişin en az 2 alan içerdiğini varsayalım.
Stéphane Chazelas

@ StéphaneChazelas OP, her zaman sekiz alana sahip olduğunu açıkça belirtti.
michaelb958 - Monica

3
@ michaelb958 Ben "açıkça" davanın abartılı olduğunu düşünüyorum, sadece biraz :)
jasonwryan

4

Kendinizi beceriksiz ve baştan aşağı bulursanız, coreutils ile aynı şeyi başarabilirsiniz:

paste <(           cut -d'|' -f1  file) \ 
      <(rev file | cut -d'|' -f1 | rev)

cutSadece ilk sütuna ilgi duyduğunuzda ya da sınırlayıcılar sabitse (yani değişken sayıda boşluk değil), awk / sed'den daha temiz ve daha küçüktür.
Sridhar Sarnobat

2

Sınırlandırılmış olan metnin ilk ve son alanlarını almaya çalışıyorsunuz |.

Günlük dosyanızın aşağıdaki gibi bir metin içerdiğini varsaydım,

foo|dog|cat|mouse|lion|ox|tiger|bar
bar|dog|cat|mouse|lion|ox|tiger|foo

Ve çıktı gibi istiyorsun

foo bar
bar foo

Eğer evet ise, o zaman işte emrinize gelir.

GNU sed aracılığıyla,

sed -r 's~^([^|]*).*\|(.*)$~\1 \2~' file

Örnek:

$ echo 'foo|dog|cat|mouse|lion|ox|tiger|bar' | sed -r 's~^([^|]*).*\|(.*)$~\1 \2~'
foo bar

Sütunlar bir boru ile sınırlandırılmamıştır | ama sütunlar halinde, sed komutunu kullanmakla ilgileniyorum ama komutunuzda yaptığınız gibi awk komutunu kullanmıyorum: sed -r 's ~ ^ ([^ |] *). * \ | (. *) $ ~ \ 1 \ 2 ~' dosyası
user70573

"Sütunlar bir boru ile sınırlandırılmamış | ancak sütunlar içindedir", yani sütunların boşluklarla ayrıldığını mı kastediyorsunuz?
Avinash Raj,

Bir örnek girişi ve bir çıktı daha iyi olurdu.
Avinash Raj,

1

Muhtemelen bunu yapmalısın sed- yine de yapardım - ama, sadece bunu henüz kimse yazmadı çünkü:

while IFS=\| read col1 cols
do  printf %10s%-s\\n "$col1 |" " ${cols##*|}"
done <<\INPUT
foo|dog|cat|mouse|lion|ox|tiger|bar
INPUT

ÇIKTI

     foo | bar
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.