ekstrak bagian dari string menggunakan bash / cut / split

121

Saya memiliki string seperti ini:

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

Saya perlu mengekstrak nama pengguna ( joebloggs) dari string ini dan menyimpannya dalam variabel.

Format string akan selalu sama dengan pengecualian joebloggsdan domain.comjadi menurut saya string dapat dibagi dua kali menggunakan cut?

Pembagian pertama akan dipisahkan :dan kami akan menyimpan bagian pertama dalam variabel untuk diteruskan ke fungsi pemisahan kedua.

Pemisahan kedua akan dipisahkan /dan menyimpan kata terakhir ( joebloggs) ke dalam variabel

Saya tahu bagaimana melakukan ini di php menggunakan array dan split tapi saya agak tersesat di bash.

Craig Edmonds
sumber

Jawaban:

333

Untuk mengekstrak joebloggsdari string ini di bash menggunakan perluasan parameter tanpa proses tambahan ...

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

Tidak bergantung pada joebloggskedalaman tertentu di jalan.


Ringkasan

Ikhtisar dari beberapa mode ekspansi parameter, untuk referensi ...

${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

Jadi #berarti cocok dari awal (pikirkan baris komentar) dan %berarti dari akhir. Satu contoh berarti terpendek dan dua contoh berarti terpanjang.

Anda bisa mendapatkan substring berdasarkan posisi menggunakan angka:

${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)

Anda juga dapat mengganti string atau pola tertentu menggunakan:

${MYVAR/search/replace}

Ada patterndalam format yang sama dengan pencocokan nama file, jadi *(karakter apa pun) adalah umum, sering kali diikuti dengan simbol tertentu seperti /atau.

Contoh:

Diberikan variabel seperti

MYVAR="users/joebloggs/domain.com" 

Hapus jalur meninggalkan nama file (semua karakter hingga garis miring):

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

Hapus nama file, tinggalkan jalur (hapus kecocokan terpendek setelah yang terakhir /):

echo ${MYVAR%/*}
users/joebloggs

Dapatkan hanya ekstensi file (hapus semua sebelum periode terakhir):

echo ${MYVAR##*.}
com

CATATAN: Untuk melakukan dua operasi, Anda tidak dapat menggabungkannya, tetapi harus menetapkan ke variabel perantara. Jadi untuk mendapatkan nama file tanpa jalur atau ekstensi:

NAME=${MYVAR##*/}      # remove part before last slash
echo ${NAME%.*}        # from the new var remove the part after the last period
domain
beroe
sumber
Saya tidak yakin apakah ini merupakan argumen yang mendukung atau menentang penggunaan grep secara kreatif, tetapi cobalah dengan VAR = / here / is / a / path: with / a / colon / inside: DNS9 = domain.com
rici
2
Manis! Dan itu dilakukan di dalam shell pelaksana, dengan demikian jauh lebih cepat daripada yang menggunakan perintah lain.
stolsvik
3
@Fadi Anda harus mengganti wildcard untuk datang sebelum usus besar, dan menggunakan #bukan %. Jika Anda hanya menginginkan bagian setelah titik dua terakhir, gunakan ${MYVAR##*:}untuk mendapatkan bagian setelah titik dua pertama, gunakan${MYVAR#*:}
beroe
4
Sobat, Anda tidak tahu berapa kali saya kembali ke jawaban ini. Terima kasih!
Joel B
1
Jawaban yang bagus! Pertanyaan: Jika pola saya adalah variabel, apakah saya akan mengetiknya seperti ini ${RET##*$CHOP}atau seperti ini ${RET##*CHOP}(atau dengan cara lain)? EDIT: Tampaknya menjadi yang pertama,${RET##*$CHOP}
Ctrl S
43

Tentukan fungsi seperti ini:

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

Dan berikan string sebagai parameter:

userName=$(getUserName "/var/cpanel/users/joebloggs:DNS9=domain.com")
echo $userName
Stefano Sanfilippo
sumber
1
Jawaban ini membantu saya mencapai tujuan saya datang ke sini. Tidak ada jawaban yang diterima dan yang ini mendapat suara saya untuk kesederhanaan.
harperville
1
Satu-satunya koreksi yang harus saya lakukan pada perintah di atas adalah menghapus ':', seperti ini echo $1 | cut -d -f 1 | xargs. 1 untuk jawaban sederhana dan rapi.
Bhushan
20

Bagaimana dengan sed? Itu akan bekerja dalam satu perintah:

sed 's#.*/\([^:]*\).*#\1#' <<<$string
  • The #sedang digunakan untuk pembagi regex bukan /karena string memiliki /di dalamnya.
  • .*/ meraih tali ke garis miring terbalik terakhir.
  • \( .. \)menandai grup tangkap. Ini adalah\([^:]*\) .
    • The [^:]mengatakan setiap karakter _except titik dua, dan *berarti nol atau lebih.
  • .* berarti sisa baris.
  • \1berarti menggantikan apa yang ditemukan di kelompok penangkapan pertama (dan satu-satunya). Ini namanya.

Berikut rincian yang cocok dengan string dengan ekspresi reguler:

        /var/cpanel/users/           joebloggs  :DNS9=domain.com joebloggs
sed 's#.*/                          \([^:]*\)   .*              #\1       #'
David W.
sumber
Diseksi super bagus!
kyb
11

Menggunakan satu sed

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

Menggunakan satu Awk:

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

Artinya, baik menggunakan sebagai pemisah bidang /atau :, nama pengguna selalu ada di bidang 5.

Untuk menyimpannya dalam variabel:

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

Penerapan yang lebih fleksibel dengan seditu tidak memerlukan nama pengguna menjadi bidang 5:

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

Artinya, hapus semuanya dari :dan seterusnya, lalu hapus semuanya hingga yang terakhir /. sedmungkin lebih cepat juga awk, jadi alternatif ini pasti lebih baik.

janos
sumber