bash / cut / split kullanarak bir dizenin bir kısmını ayıklayın


121

Bunun gibi bir dizem var:

/var/cpanel/users/joebloggs:DNS9=domain.com

Kullanıcı adını ( joebloggs) bu dizeden çıkarmam ve bir değişkende saklamam gerekiyor.

Dize biçimi, hariç olmak üzere her zaman aynı olacaktır joebloggsve domain.combu yüzden dizenin iki kez cut? Kullanılarak bölünebileceğini düşünüyorum.

İlk bölme bölünür :ve ikinci bölme işlevine geçmek için ilk parçayı bir değişkende saklardık.

İkinci bölme /, son kelimeyi ( joebloggs) bir değişkene böler ve saklar

Bunu php'de diziler ve bölmeler kullanarak nasıl yapacağımı biliyorum ama bash'da biraz kayboldum.

Yanıtlar:


333

joebloggsHerhangi bir ekstra işlem olmadan parametre genişletmeyi kullanarak bu dizeden bash'ta çıkarmak için ...

MYVAR="/var/cpanel/users/joebloggs:DNS9=domain.com" 

NAME=${MYVAR%:*}  # retain the part before the colon
NAME=${NAME##*/}  # retain the part after the last slash
echo $NAME

Yolda joebloggsbelirli bir derinlikte olmaya bağlı değildir .


özet

Referans için birkaç parametre genişletme moduna genel bakış ...

${MYVAR#pattern}     # delete shortest match of pattern from the beginning
${MYVAR##pattern}    # delete longest match of pattern from the beginning
${MYVAR%pattern}     # delete shortest match of pattern from the end
${MYVAR%%pattern}    # delete longest match of pattern from the end

Yani #baştan eşleştirme (bir yorum satırı düşünün) ve %sondan itibaren anlamına gelir. Bir örnek en kısa, iki örnek en uzun anlamına gelir.

Sayıları kullanarak konuma göre alt dizeler elde edebilirsiniz:

${MYVAR:3}   # Remove the first three chars (leaving 4..end)
${MYVAR::3}  # Return the first three characters
${MYVAR:3:5} # The next five characters after removing the first 3 (chars 4-9)

Ayrıca, belirli dizeleri veya desenleri kullanarak da değiştirebilirsiniz:

${MYVAR/search/replace}

patternDosya adı eşleştirme aynı biçimde, yani *(herhangi bir karakter) sıklıkla gibi belirli bir sembol ardından yaygındır /ya.

Örnekler:

Gibi bir değişken verildiğinde

MYVAR="users/joebloggs/domain.com" 

Dosya adını bırakan yolu kaldırın (eğik çizgiye kadar tüm karakterler):

echo ${MYVAR##*/}
domain.com

Dosya adını kaldırın, yolu bırakın (sondan sonraki en kısa eşleşmeyi silin /):

echo ${MYVAR%/*}
users/joebloggs

Yalnızca dosya uzantısını alın (son noktadan önceki tümünü kaldırın):

echo ${MYVAR##*.}
com

NOT: İki işlemi yapmak için bunları birleştiremezsiniz, ancak bir ara değişken atamanız gerekir. Yani dosya adını yol veya uzantı olmadan almak için:

NAME=${MYVAR##*/}      # remove part before last slash
echo ${NAME%.*}        # from the new var remove the part after the last period
domain

Bunun grep'in yaratıcı kullanımı lehinde mi yoksa aleyhinde mi olduğundan emin değilim, ancak VAR = / burada / olur / a / yol: ile / a / iki nokta / iç: DNS9 = alan.com
rici

2
Tatlı! Ve bu, çalıştırma kabuğunun içinde yapılır, böylece diğer komutları kullananlardan çok daha hızlıdır.
stolsvik

3
@Fadi Joker karakterin iki nokta üst üste işaretinden önce gelmesi ve #yerine kullanmanız gerekir %. Yalnızca son iki noktadan sonraki bölümü istiyorsanız ${MYVAR##*:}, ilk iki ${MYVAR#*:}
noktadan

4
Arkadaşım, bu cevaba kaç kez geri döndüğümü bilmiyorsun. Teşekkür ederim!
Joel B

1
Mükemmel cevap! Soru: Desenim bir değişken olsaydı, bunu şu şekilde mi ${RET##*$CHOP}yoksa böyle ${RET##*CHOP}mi (veya başka bir şekilde) yazardım? DÜZENLEME: Eski gibi görünüyor${RET##*$CHOP}
Ctrl S

43

Bunun gibi bir işlevi tanımlayın:

getUserName() {
    echo $1 | cut -d : -f 1 | xargs basename
}

Ve dizeyi bir parametre olarak iletin:

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.com")
echo $userName

1
Bu cevap, buraya ne için geldiğimi elde etmeme yardımcı oldu. Kabul edilmiş bir cevap yok ve bu basitlik için oyumu alıyor.
harperville

1
Yukarıdaki komutta yapmam gereken tek düzeltme, bunun gibi ':' öğesini kaldırmaktı echo $1 | cut -d -f 1 | xargs. Basit ve temiz anlar için +1.
Bhushan

20

Ya sed? Bu tek bir komutla çalışacak:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • #Yerine düzenli ifade bölücülerin kullanılmakta olan /dize beri /içinde.
  • .*/ dizeyi son ters eğik çizgiye kadar yakalar.
  • \( .. \)bir yakalama grubunu işaretler. Bu \([^:]*\).
    • İki [^:]nokta hariç herhangi bir karakter ve *sıfır veya daha fazla anlamına gelir.
  • .* satırın geri kalanı anlamına gelir.
  • \1ilk (ve tek) yakalama grubunda bulunanların yerine geçmek anlamına gelir. İsim bu.

Dize ile normal ifade ile eşleşen döküm şu şekildedir:

        /var/cpanel/users/           joebloggs  :DNS9=domain.com joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'

Süper güzel diseksiyon!
kyb

11

Tek bir sed kullanma

echo "/var/cpanel/users/joebloggs:DNS9=domain.com" | sed 's/.*\/\(.*\):.*/\1/'

10

Tek bir Awk kullanarak:

... | awk -F '[/:]' '{print $5}'

Diğer bir deyişle, alan ayırıcı olarak /veya kullanmak :, kullanıcı adı her zaman alan 5'tedir.

Bir değişkende saklamak için:

username=$(... | awk -F '[/:]' '{print $5}')

sedKullanıcı adının 5. alan olmasını gerektirmeyen daha esnek bir uygulama :

... | sed -e s/:.*// -e s?.*/??

Yani, her şeyi :ve ötesindeki her şeyi silin ve ardından her şeyi sonuna kadar silin /. sedmuhtemelen daha hızlıdır awk, bu nedenle bu alternatif kesinlikle daha iyidir.

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.