2012-03-28 10 views
22

Oto myscript.sh

#!/bin/bash 
for i in {1..$1}; 
do 
    echo $1 $i; 
done 

Jeśli biegnę myscript.sh 3 wyjście jest

3 {1..3} 

zamiast

3 1 
3 2 
3 3 

Oczywiście $3 zawiera prawidłową wartość, więc dlaczego for i in {1..$1} zachowuje się tak samo, jak gdybym napisałem for i in {1..3} bezpośrednio?

+1

Twój przykład skrypt będzie działać w obu ksh93 i zsh . –

Odpowiedz

43

należy użyć stylu C dla pętli do wykonania tego:

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

Pozwala to uniknąć zewnętrznych poleceń i nieprzyjemnych instrukcji eval.

+0

Nie działa dla mnie 'test.sh: linia 1: ((: i <=: błąd składni: oczekiwany operand (błąd to" <= ")' – Temak

+0

@Temak używasz 'bash'? Czy twój shebang' #!/bin/bash' lub '#!/bin/sh'? – jordanm

+0

@jordann, plik zawiera tylko te trzy linie: Używam GNU bash, wersja 4.3.11 (1) -release (x86_64-pc- linux-gnu). Uruchamiam skrypt 'bash test.sh' – Temak

18

Ponieważ rozszerzenie nawiasu występuje przed rozwinięciem zmiennych. http://www.gnu.org/software/bash/manual/bashref.html#Brace-Expansion.

Jeśli chcesz użyć szelek, można więc coś ponuro tak:

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

Podsumowanie: Bash jest niedobre.

+1

Heh, +1 za odpowiedź, -0,5 za podłe. –

+1

@glennjackman: Wow, mówisz, że liczne zasady ekspansji i ucieczki Basha nie są nikczemne? –

+0

Czuję się brudna za wypowiadanie +1 w odpowiedzi dotyczącej 'eval'. Re: vile: 'bash' nie jest nikczemny, ale to trochę tak, jakbyś pił alkohol prosto. Niektórzy ludzie lubią to, ale na początku trudno się nie udusić, im więcej robisz, tym mniej się tym przejmuje. – Sorpigal

11

Można użyć seq polecenie:

for i in `seq 1 $1` 

Albo można użyć stylu C for...loop:

for((i=1;i<=$1;i++)) 
+0

Preferowana jest pętla w stylu C nad zewnętrznym poleceniem seq. – jordanm

+0

@jordanm To dobry pomysł. – kev

+0

wery good, z seq można zmienić krok! –

1

Wiem, że wspomniałeś bash w nagłówku, ale dodam, że "dla mnie w {$ 1 .. $ 2}" działa zgodnie z przeznaczeniem w zsh. Jeśli twój system ma zainstalowany zsh, możesz po prostu zmienić swój shebang na zsh.

Używanie zsh z przykładem "dla mnie w {$ 1 .. $ 2}" ma także dodatkową zaletę, że 1 dolar może być mniejszy niż 2 USD i nadal działa, coś, co wymagałoby sporo bałaganu, gdybyś chciał ten rodzaj elastyczności z pętlą w stylu C.

0

Oto sposób, aby rozwinąć zmiennych wewnątrz szelki bez eval:

end=3 
declare -a 'range=({'"1..$end"'})' 

teraz mamy piękny tablicę liczb:

for i in ${range[@]};do echo $i;done 
1 
2 
3 
Powiązane problemy