Yanıtlar:
Kullanım cutile _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 echoHere 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 IFSsı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, readyerleşimi kullanmaktır .
IFS=_ read -r first second third fourth trail <<'EOF'
one_two_three_four_five
EOF
unset IFSdö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 IFSgeri 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ü readburada-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 awkcevap 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 $abunun 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 -fyok (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 ...
readarraybu durum için kullanımı daha kolay olabilir.
Sizinle zshdizgiyi (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 -filk çö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 ...