Bash küme ayracı genişletmesinde bir değişken kullanabilir miyim?


10

Aşağıda gerçekleştirmeye çalıştığım şey için sözde kod bir tür:

#!/bin/bash

# I already have the variable below figured out (positive integer):
numlines=$([returns number of lines containing specific characters in a file])

# This is basically what I want to do with it:
for i in {1..$numlines}; do
    # the part below is already figured out as well:        
    do some other stuff
done

`` 1..n} '' sırasına gerçek sayıyı ekleyerek komut satırından düzgün çalıştırabilirim. Buraya bir değişken eklemenin mümkün olup olmadığını ve bunu nasıl yapacağınızı bilmem gerekiyor.

  • Ben denedim exportbunu ing
  • Değişken kendisini dizinin içindeki kıvırcık parantez içine koymayı denedim: {1..${numlines}}
  • Ben genişletmek umuduyla çift tırnak koyarak denedim: {1.."$numlines"}
  • Kaçmayı denedim $:{1..\$numlines}

set -[something]Bu değişkenin genişletilmesi için bir komut kullanmam gerekir mi? Kullanmanın bazı biçimlerini bile denedim eval... hepsi boşuna.

Sadece eksik olduğum basit ya da belirsiz bir şey olup olmadığını ya da artık zaman kaybetmeden önce bu mümkün olup olmadığını bilmem gerekiyor.

Gerektiği gibi çalışmasını sağlamak için gerçekten, gerçekten hackish bir şekilde bir araya getirebilirim, ancak mümkünse bundan kaçınmak ve bunu yapmak için doğru yolu öğrenmek istiyorum.


Yanıtlar:


11

Ne yazık ki, bu genişletmede (AFAIK) bir değişken kullanmanın bir yolu yoktur, çünkü küme genişletmesinden sonra değişken genişletme gerçekleşir.

Neyse ki, aynı işi yapan bir araç var.

for i in $(seq 1 $numlines); do
    # stuff
done

seqGNU coreutils'den; POSIX'te nasıl yapılacağını bilmiyorum.


1
(Artı 1). seqGNU sistemleri için iyidir ve doğru hatırlarsam en son OSX. Diğer BSD sistemlerinde bunun yerine jot kullanılabilir.
John1024

seqMükemmel çalışıyor. Hemen cevap verdiğiniz için çok teşekkür ederim.
rubynorails

Bu sorumun bir parçası değildi - ama bunu ters sırada yapmak için sözdizimi (varsa) {16..1}nedir? $(seq $numlines 1)işe yaramadı. Sanırım her zaman yapabilirim man seq, ama sadece birinin başının üstünü bilip bilmediğini merak ediyorum.
rubynorails

1
Sadece bu bağlantıdan tersine nasıl yapılacağını anladım -for i in $(seq $numlines -1 1)
rubynorails

seq ${numlines} -1 0
DopeGhoti

10

Elbette. Bir tamsayı değişkenini artıran bir for döngüsü istiyorsanız, bir tamsayı değişkenini arttıran fordöngü biçimini kullanın (veya daha genel olarak döngü değişken (ler) i üzerinde aritmetik gerçekleştirir).

for ((i=1; i<=numlines; i++)); do  done

Bu yapı bash (ve ksh93 ve zsh) 'de çalışır, ancak düz sh'de çalışmaz. Düz sh'de bir while döngüsü ve test ( [ … ]) yapısı kullanın.

i=1
while [ "$i" -le "$numlines" ]; do
  
  i=$((i+1))
done

8

seqTom Hunt'ın işaret ettiği gibi bunun olağan çözümü gibi göründüğünden kaçınmanız gerekiyorsa , evalkesinlikle bunu yapabilir (ancak, bunu teşvik etmem):

eval 'for i in {1..'$numlines'}; do echo $i; done'

{} Genişlemesinden kaçınarak POSIX'te kalabilir ve aşağıdaki konularda matematik ve tamsayı karşılaştırmaları yapabilirsiniz $numlines:

while [ ! "$numlines" -eq 0 ]; do
     echo "$numlines"
     : $((numlines-=1))
done

POSIX dışında, bashve kshve zshayrıca C tarzı var fordöngüler:

for((i=0; i<numlines; i++)); do echo $i; done

1
Bu yanıtı da gerçekten takdir ediyorum. İken seqbenim senaryo için para cezası çalışmış ve en basit çözümü gibi görünüyordu, (hatta POSIX) diğer alternatifler de var olduğunu bilmek iyidir. Bunun için teşekkürler.
rubynorails

2
Kullanmak için gerçekten bir neden yok eval; küme ayracı genişlemeniz varsa, C stili döngüye sahipsiniz.
chepner

@PSkocik - 2 cevap seçebilseydim, bunu da seçerdim. Bunu tersine yapmam gerektiği gerçeğiyle karşılaştığımda, evalörneğin en basitiydi ve beni kullanarak bunu yapmanın alternatif bir yolunu aramaktan kurtarırdı seq. whileDöngü benim için biraz hantal. Ben şeyleri kısa ve tatlı tutmak istiyorum, ve asla 0 veya 1 değerini forvererek C tarzı döngü işe alamadım. iAsla doğru dönmedi ve her zaman biraz kapalı idi. Eminim doğru çalışmak için ince ayar yapılabilir, ancak bunlar kesinlikle yararlı çözümlerdir.
rubynorails

evalDöngünün vücudun içinde önemsiz olmayan bir şey varsa yaklaşım problemlidir. Böyle iki döngüyü iç içe yerleştirmeniz gerekiyorsa çok okunabilir olmayacağını düşünüyorum.
kasperd
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.