Bash'deki bir komutun çıktısının ilk kelimesi nasıl alınır?


127

Ben örneğin bir komutu vardır: echo "word1 word2". Bir boru ( |) koymak ve komuttan word1 almak istiyorum .

echo "word1 word2" | ....

Borudan sonra ne koyacağımı bilmiyorum.

Yanıtlar:


201

Awk, sondaki beyaz boşlukla uğraşmak zorunda kalırsanız iyi bir seçenektir çünkü sizin için onu halleder:

echo "   word1  word2 " | awk '{print $1;}' # Prints "word1"

Cut bununla ilgilenmez:

echo "  word1  word2 " | cut -f 1 -d " " # Prints nothing/whitespace

Burada 'kes' hiçbir şey / boşluk yazdırmaz, çünkü bir boşluktan önceki ilk şey başka bir boşluktur.


Noktalı virgül gerekli mi?
Alice Purcell

1
"Sonda" değil, "başında" boşluk olmalıdır (dizenin başında).
user202729

@AlicePurcell Olmadan denedim; ve benim için çalıştı (MBP 10.14.2)
Samy Bencherif

1
Dize boşlukla o awk komut sınırlayıcı olarak örneğin "firstWord, secondWord" ise bu işe yaramaz
Roger Oba

@RogerOba Bu OP'nin sorusu değildi, ancak -F","varsayılan alan ayırıcıyı (boşluk) virgülle geçersiz kılmak için kullanabilirsiniz .
pjd

70

harici komutlar kullanmaya gerek yok. Bash'in kendisi işi yapabilir. "Kelime1 kelime2" yi bir yerden aldığınızı ve bir değişkende depolandığınızı varsayarak, örn.

$ string="word1 word2"
$ set -- $string
$ echo $1
word1
$ echo $2
word2

şimdi isterseniz başka bir değişkene $ 1 veya $ 2 vb. atayabilirsiniz.


11
+1 kabuk yerleşiklerini kullanmak için ve stdin. @Matt M. , aynı şekilde aktarılıyor --demektir . argümanları içine boşluk-ayrılır , , , vb - sadece bir Bash programı değerlendirir bağımsız değişkenleri (örneğin, çek zaman gibi , vs.), bu yaklaşım bölmek için kabuk eğilimi yararlanır ihtiyacını ortadan kaldırarak, otomatik olarak bağımsız değişken olarak ya da . stdin$stringstdinstdin$1$2$3$1$2stdinawkcut
Caleb Xu

3
@CalebXu Standart değil set, kabuk argümanlarını ayarlar.
Guido

9
word1=$(IFS=" " ; set -- $string ; echo $1)IFS'yi sözcükler arasındaki boşluğu doğru şekilde tanıyacak şekilde ayarlayın. 1 $ 'lık orijinal içeriğin bozulmasını önlemek için parantez içine alın.
Steve Pitchers

Bu, yol adı genişletmesine tabi olduğu için bozulmuştur. İle deneyin string="*". Sürpriz.
gniourf_gniourf

32

Bence etkili bir yol bash dizilerinin kullanılması:

array=( $string ) # do not use quotes in order to allow word expansion
echo ${array[0]}  # You can retrieve any word. Index runs from 0 to length-1

Ayrıca, bir boru hattındaki dizileri doğrudan okuyabilirsiniz:

echo "word1 word2" | while read -a array; do echo "${array[0]}" ; done

1
echo " word1 word2 " | { read -a array ; echo ${array[0]} ; }
Boontawee Home

Bu, yol adı genişletmesine tabi olduğu için bozulmuştur. İle deneyin string="*". Sürpriz.
gniourf_gniourf

whileHer satırdaki her ilk kelimeyi almak için sözdizimini kullanın . Aksi takdirde, Boontawee Home yaklaşımını kullanın. Ayrıca, echo "${array[0]}"gniourf-gniourf tarafından fark edildiği gibi genişlemeyi önlemek için alıntı yapıldığını lütfen unutmayın .
Isaías

Sözcük sayısından daha büyük olan bir dizi dizinine erişmeye çalışırsanız, bir hata almazsınız. Sadece boş bir satır alacaksınız
Dhumil Agarwal

26
echo "word1 word2 word3" | { read first rest ; echo $first ; }

Bu, harici komutları kullanmama ve $ 1, $ 2, vb. Değişkenleri olduğu gibi bırakma avantajına sahiptir.


Değişkenleri $1, $2, …olduğu gibi bırakmak, komut dosyası yazmak için son derece yararlı bir özelliktir!
Serge Stroobandt

15

Başta boşluk olmadığından eminseniz, bash parametresi değiştirmeyi kullanabilirsiniz:

$ string="word1  word2"
$ echo ${string/%\ */}
word1

Tek alandan kaçmaya dikkat edin. Daha fazla ikame modeli örneği için buraya bakın . Bash> 3.0'a sahipseniz, baştaki boşluklarla başa çıkmak için düzenli ifade eşleştirmesini de kullanabilirsiniz - buraya bakın :

$ string="  word1   word2"
$ [[ ${string} =~ \ *([^\ ]*) ]]
$ echo ${BASH_REMATCH[1]}
word1

11

Awk deneyebilirsin

echo "word1 word2" | awk '{ print $1 }'

Awk ile istediğiniz herhangi bir kelimeyi seçmek gerçekten çok kolay (1 $, 2 $, ...)


11

Kabuk parametresi genişletmeyi kullanma %% *

İşte kabuk parametresi genişletmeyi kullanan başka bir çözüm . İlk kelimeden sonra birden fazla boşlukla ilgilenir. İlk kelimenin önündeki boşluklarla ilgilenmek, bir ek genişletme gerektirir.

string='word1    word2'
echo ${string%% *}
word1

string='word1    word2      '
echo ${string%% *}
word1

açıklama

%%Anlamına hangi silme olası en uzun maç  *içinde (boşluk olursa olsun diğer karakterlerin herhangi numarası takip) sondaki parçası string.


9

Hız açısından en iyi yanıtlardan birkaçının nasıl ölçüldüğünü merak ettim. Aşağıdakileri test ettim:

1 @ mattbh's

echo "..." | awk '{print $1;}'

2 @ hayalet

string="..."; set -- $string; echo $1

3 @ boontawee-home

echo "..." | { read -a array ; echo ${array[0]} ; }

ve 4 @ boontawee-home

echo "..." | { read first _ ; echo $first ; }

Bunları, 5 harfli 215 kelimelik bir test dizesi kullanarak, macOS'ta bir Zsh terminalinde bir Bash komut dosyasında Python'un timeit ile ölçtüm. Her ölçümü beş kez yaptım (sonuçların tümü 100 döngü içindi, en iyisi 3) ve sonuçların ortalamasını aldı:

method       time
--------------------------------
1. awk       9.2ms
2. set       11.6ms (1.26 * "1")
3. read -a   11.7ms (1.27 * "1")
4. read      13.6ms (1.48 * "1")

İyi iş, seçmenler 👏 Oylar (bu yazı itibariyle) çözümün hızına uyuyor!


Tire dizileri desteklemediğinden ( read -atire içinde geçersizdir), tire ile 3'ü ölçebilmeniz garip .
gniourf_gniourf

Evet bu tuhaf. Birini reddettim, hız testlerini yaptım, sonra "bunu neden dışarıda bıraktım" diye düşündüm ve ekledim. Şimdi kaldırıyorum ve daha sonra bir hata yapmadığımdan emin olmak için işleri tekrar çalıştırabilirim
henry

6
echo "word1 word2" | cut -f 1 -d " "

cut, "" (-d "") dizesi ile ayrılmış alanlar listesinden 1. alanı (-f 1) keser


bu bir yol, ancak daha sonra
kelime2'yi

evet, awk çözümü daha iyi.
lajuette

3

read senin arkadaşın:

  • String bir değişkendeyse:

    string="word1 word2"
    read -r first _ <<< "$string"
    printf '%s\n' "$first"
  • Bir boru üzerinde çalışıyorsanız: ilk durum: yalnızca ilk satırın ilk kelimesini istersiniz:

    printf '%s\n' "word1 word2" "line2" | { read -r first _; printf '%s\n' "$first"; }

    ikinci durum: her satırın ilk kelimesini istiyorsunuz:

    printf '%s\n' "word1 word2" "worda wordb" | while read -r first _; do printf '%s\n' "$first"; done

Önde gelen boşluklar varsa bunlar işe yarar:

printf '%s\n' "   word1 word2" | { read -r first _; printf '%s\n' "$first"; }

0

Perl, awk'ın işlevselliğini içerdiğinden, bu da perl ile çözülebilir:

echo " word1 word2" | perl -lane 'print $F[0]'

0

Perl, awk veya python içermeyen ve bunun yerine sed ile yapan gömülü bir cihazla çalışıyordum. İlk kelimeden önce ( cutve bashçözümlerinin ele almadığı) birden çok boşluğu destekler .

VARIABLE="  first_word_with_spaces_before_and_after  another_word  "
echo $VARIABLE | sed 's/ *\([^ ]*\).*/\1/'

psSadece bash kullanan diğer çözümler pshizalamak için kullanılan ilk boşlukları kaldıramadığından, bu işlem kimlikleri için grep yaparken çok yararlıydı .

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.