Yanıtlar:
Kullanım cut
ile _
alan ayırıcı olarak ve istenen alanları olsun:
A="$(cut -d'_' -f2 <<<'one_two_three_four_five')"
B="$(cut -d'_' -f4 <<<'one_two_three_four_five')"
Ayrıca echo
Here string yerine pipet kullanabilir ve kullanabilirsiniz :
A="$(echo 'one_two_three_four_five' | cut -d'_' -f2)"
B="$(echo 'one_two_three_four_five' | cut -d'_' -f4)"
Örnek:
$ s='one_two_three_four_five'
$ A="$(cut -d'_' -f2 <<<"$s")"
$ echo "$A"
two
$ B="$(cut -d'_' -f4 <<<"$s")"
$ echo "$B"
four
$ echo $FILE
my_user/my_folder/file.csv
$ A="$(cut -d'/' -f2 <<<"$FILE")"
$ echo $A
[file]*
Burada neler olduğunu biliyor musunuz?
echo "${s##*_}"
Yalnızca POSIX sh yapılarını kullanarak , bir seferde bir sınırlayıcıyı ayrıştırmak için parametre değiştirme yapılarını kullanabilirsiniz . Bu kodun gerekli sayıda alan olduğunu varsaydığını, aksi takdirde son alanın tekrarlandığını unutmayın.
string='one_two_three_four_five'
remainder="$string"
first="${remainder%%_*}"; remainder="${remainder#*_}"
second="${remainder%%_*}"; remainder="${remainder#*_}"
third="${remainder%%_*}"; remainder="${remainder#*_}"
fourth="${remainder%%_*}"; remainder="${remainder#*_}"
Alternatif olarak, joker genişlemesi devre dışı bırakılmış ve IFS
sınırlayıcı karakterine ayarlanmış olarak işaretsiz bir parametre değiştirme kullanabilirsiniz (sınırlayıcı tek boşluklu olmayan tek bir karakter ise veya herhangi bir boşluk dizisi sınırlayıcıysa işe yarar).
string='one_two_three_four_five'
set -f; IFS='_'
set -- $string
second=$2; fourth=$4
set +f; unset IFS
Bu konumsal parametreleri gizler. Bunu bir fonksiyonda yaparsanız, sadece fonksiyonun konumsal parametreleri etkilenir.
Yine bir başka yaklaşım, read
yerleşimi kullanmaktır .
IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF
unset IFS
dönmüyor IFS
. Bundan sonra birisi OldIFS="$IFS"
OldIFS içinde boş bir değere sahip olacaktır. Ayrıca, önceki IFS değerinin varsayılan olduğu varsayılmaktadır, ki bu mümkün değildir (ve faydalıdır). Tek doğru çözüm, old="$IFS"
IFS = "$ old" ile depolamak ve daha sonra geri yüklemek. Veya ... bir alt kabuk kullanın (...)
. Ya da daha iyisi, cevabımı oku.
unset IFS
geri yüklemez IFS
, ancak alan efektini varsayılan efekte döndürür. Evet, bu bir sınırlama, ancak pratikte genellikle kabul edilebilir bir sınırdır. Alt kabuktaki problem, veriyi çıkarmamız gerektiğidir. Sonunda devleti değiştirmeyen bir çözüm gösteriyorum read
. (POSIX kabukları içinde çalışır, ancak IIRC Bourne kabuğunda değil çünkü read
burada-belge nedeniyle bir alt kabukta çalıştırılır .) <<<
Cevabınızdaki gibi kullanmak sadece ksh / bash / zsh içinde çalışan bir değişkendir.
user/my_folder/[this_is_my_file]*
? Bu adımları takip ederken elde ettiğim şey[this_is_my_file]*
/
.
Bir awk
cevap görmek istedim, işte bir tane:
A=$(awk -F_ '{print $2}' <<< 'one_two_three_four_five')
B=$(awk -F_ '{print $4}' <<< 'one_two_three_four_five')
awk -F_ '{print $NF}' <<< 'one_two_3_4_five'
En basit yol (<<< ile kabukları için):
IFS='_' read -r a second a fourth a <<<"$string"
Bir kabuk şikayet ettiğinden $a
bunun yerine geçici bir değişken kullanmak $_
.
Tam bir komut dosyasında:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<<"$string"
echo "$second $fourth"
IFS değişmiyor, sorun set -f
yok (Pathname genişletme) Konumsal parametrelerde değişiklik yok ("$ @").
IFS'yi değiştirmeden tüm mermilere (evet, tüm POSIX dahil) taşınabilir bir çözüm için veya set -f
(biraz daha karmaşık) heredoc eşdeğerini kullanın:
string='one_two_three_four_five'
IFS='_' read -r a second a fourth a <<-_EOF_
$string
_EOF_
echo "$second $fourth"
Bu çözümlerin (hem here-doc hem de kullanımın <<<
tüm takip eden yeni satırları kaldıracağını anlayın .
Ve bunun "bir liner" değişken içeriğine göre tasarlandığını anlayın .
Çok liner'ler için çözümler mümkündür, ancak daha karmaşık yapılara ihtiyaç vardır.
Bash 4.4 sürümünde çok basit bir çözüm mümkün
readarray -d _ -t arr <<<"$string"
echo "array ${arr[1]} ${arr[3]}" # array numbers are zero based.
POSIX kabukları diziler olmadığından, POSIX kabukları için eşdeğer yoktur.
Dizileri olan kabukları için basit olabilir:
(attsh, lksh, mksh, ksh ve bash çalıştığı test edilmiştir)
set -f; IFS=_; arr=($string)
Ancak değişkenleri ve seçenekleri saklamak ve sıfırlamak için birçok ek tesisat ile:
string='one_* *_three_four_five'
case $- in
*f*) noglobset=true; ;;
*) noglobset=false;;
esac
oldIFS="$IFS"
set -f; IFS=_; arr=($string)
if $noglobset; then set -f; else set +f; fi
echo "two=${arr[1]} four=${arr[3]}"
Zsh'de, diziler 1'de başlar ve dizgiyi varsayılan olarak bölmez.
Bu yüzden, bu çalışmayı zsh ile yapmak için bazı değişiklikler yapılması gerekiyor.
read
OP, 76. ve 127. elementleri uzun bir dizeden çıkarmak istemediği sürece kullanılan çözümler basit ...
readarray
bu durum için kullanımı daha kolay olabilir.
Sizinle zsh
dizgiyi (on _
) bir diziye bölebilirsiniz :
elements=(${(s:_:)string})
ve daha sonra dizi indeksi aracılığıyla her bir öğeye erişin:
print -r ${elements[4]}
İçinde unutmayın zsh
(aksine ksh
/ bash
) dizi indeksleri 1 başlayacak .
set -f
ilk çözüme uyarı eklemeyi unutmayın . ... *
belki yıldız olabilir ?
set -f
? read
/ Kullanmıyorum IFS
. Çözümlerimi bir dize *_*_*
ya da başka bir şeyle deneyin ...
Başka bir awk örneği; anlaşılması daha kolay.
A=\`echo one_two_three_four_five | awk -F_ '{print $1}'\`
B=\`echo one_two_three_four_five | awk -F_ '{print $2}'\`
C=\`echo one_two_three_four_five | awk -F_ '{print $3}'\`
... and so on...
Değişkenlerle de kullanılabilir.
Farz edin:
this_str = "one_two_three_four_five"
Sonra aşağıdakiler işe yarar :
A = `echo $ {this_str} | awk -F_ '{print $ 1}' `
B =` echo $ {this_str} | awk -F_ '{print $ 2}' `
C =` echo $ {this_str} | awk -F_ '{3 $ yazdırın}' `
... ve diğerleri ...