Bagaimana cara mendapatkan char pada posisi tertentu dari string di skrip shell?

22

Bagaimana cara mendapatkan char pada posisi tertentu dari string di skrip shell?

Tom Brito
sumber

Jawaban:

36

Di bash dengan "Ekspansi Parameter" $ {parameter: offset: length}

$ var=abcdef
$ echo ${var:0:1}
a
$ echo ${var:3:1}
d

Sunting: Tanpa ekspansi parameter (tidak terlalu elegan, tapi itu yang pertama kali saya ingat)

$ charpos() { pos=$1;shift; echo "$@"|sed 's/^.\{'$pos'\}\(.\).*$/\1/';}
$ charpos 8 what ever here
r
forcefsck
sumber
1
gnu.org/software/bash/manual/… memiliki rincian lebih lanjut
jsbillings
Tampaknya bukan POSIX: pubs.opengroup.org/onlinepubs/009695399/utilities/…
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
Anda juga dapat mengatur offset 'dari ujung' seperti ituecho ${var: -2:1}
Vassilis
Sintaks itu berasal dari ksh93 dan juga didukung oleh zshdan mksh.
Stéphane Chazelas
6

Alternatif untuk ekspansi parameter adalah expr substr

substr STRING POS LENGTH
    substring of STRING, POS counted from 1

Sebagai contoh:

$ expr substr hello 2 1
e
dogbane
sumber
keren, seharusnya sudah periksa expr lebih teliti.
forcefsck
1
Walaupun ini tampaknya bekerja dengan expr dari GNU coreutils, substrtidak termasuk dalam expr dari FreeBSD, NetBSD atau OS X. Ini bukan solusi portabel.
ghoti
@ ghoti, perhatikan bahwa pada substrawalnya bukan merupakan ekstensi GNU. Implementasi asli exprberasal dari PWB Unix di akhir 70-an dan telah substr(tetapi tidak :).
Stéphane Chazelas
@ StéphaneChazelas, terima kasih telah menambahkan perspektif sejarah. :) Meskipun saya cukup yakin penggunaan PWB tidak relevan dengan OP, selalu menyenangkan untuk melacak fitur dan perubahan selama beberapa dekade. GNU cenderung menjadi standar banyak orang, tetapi secara umum, saya pikir saya akan menghindari menggunakan opsi yang tidak jelas POSIX , dan diketahui hilang dari unices utama.
ghoti
5

cut -c

Jika variabel tidak mengandung baris baru yang dapat Anda lakukan:

myvar='abc'
printf '%s\n' "$myvar" | cut -c2

output:

b

awk substr adalah alternatif POSIX lain yang berfungsi bahkan jika variabel memiliki baris baru:

myvar="$(printf 'a\nb\n')" # note that the last newline is stripped by
                           # the command substitution
awk -- 'BEGIN {print substr (ARGV[1], 3, 1)}' "$myvar"

output:

b

printf '%s\n'adalah untuk menghindari masalah dengan karakter pelarian: /programming//a/40423558/895245 misalnya:

myvar='\n'
printf '%s\n' "$myvar" | cut -c1

output \ seperti yang diharapkan.

Lihat juga: /programming/1405611/extracting-first-two-characters-of-a-string-shell-scripting

Diuji di Ubuntu 19,04.

Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
sumber
printf '%s' "$myvar" | cut -c2bukan POSIX karena output printfbukan teks kecuali $myvardiakhiri dengan karakter baris baru. Jika tidak, asumsi variabel tidak mengandung karakter baris baru karena cutmemotong setiap baris inputnya.
Stéphane Chazelas
Yang awksatu akan lebih efisien dan dapat diandalkan denganawk -- 'BEGIN {print substr (ARGV[1], 2, 1)}' "$myvar"
Stéphane Chazelas
Perhatikan bahwa dengan versi GNU saat ini cut, itu tidak berfungsi untuk karakter multi-byte (sama untuk mawk atau busybox awk)
Stéphane Chazelas
@ StéphaneChazelas terima kasih untuk poinnya. Saya tidak mengerti apa yang Anda maksud pada yang pertama: maksud Anda itu printf 'abc '| cut -c2salah karena tidak \n(ini saya tidak tahu), atau bahwa perintah akan gagal jika myvar memiliki baris baru (ini saya setuju)?
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
1
Perilaku cuttidak ditentukan jika input bukan teks (meskipun cutimplementasi diperlukan untuk menangani garis atau panjang sewenang-wenang). Output dari printf abcbukan teks karena tidak diakhiri dengan karakter baris baru. Dalam praktik tergantung pada implementasinya, jika Anda menyalurkannya cut -c2, Anda mendapatkan keduanya b, b<newline>atau tidak sama sekali. Anda harus printf 'abc\n' | cut -c2mendapatkan perilaku yang ditentukan oleh POSIX (yang diperlukan untuk menampilkan b<newline>)
Stéphane Chazelas
1

Dengan zshatau yash, Anda akan menggunakan:

$ text='€$*₭£'
$ printf '%s\n' "${text[3]}"
*

(dalam zsh, Anda dapat mempersingkat printf '%s\n' $text[3]).

Stéphane Chazelas
sumber
0

Anda dapat menggunakan perintah cut. Untuk mendapatkan posisi ke-3:

echo "SAMPLETEXT" | cut -c3

Periksa tautan ini http://www.folkstalk.com/2012/02/cut-command-in-unix-linux-examples.html

( Kasus lanjutan ) Namun, memodifikasi IFS juga merupakan hal yang baik, terutama ketika input Anda memiliki spasi. Dalam hal itu saja, gunakan yang di bawah ini

saveifs=$IFS
IFS=$(echo -en "\n\b")
echo "SAMPLETEXT" | cut -c3
IFS=$saveifs
Midhun Jose
sumber
Saya tidak bisa melihat bagaimana IFSikut bermain dalam kode yang telah Anda posting.
Kusalananda