1. argüman hariç $ @


36

Bu şekilde çalışan bir kabuk betiği yazmam gerekiyor:

./myscript arg1 arg2_1 arg2_2 arg2_3 ....... arg2_#

script içinde bir for döngüsü var

for i in $@

Ancak bildiğim gibi, $ @ 1 - $ ($ # - 1) arasında bir değer içeriyor. Fakat benim programım için $ 1, $ 2 $ 'dan $ 4 $' a kadar farklı. Vb 2 $ 'dan sonuna kadar döngü yapmak istiyorum. Teşekkür ederim:)

Yanıtlar:


47

İlk olarak, $@tırnak işaretleri olmadan bir anlam ifade etmediğini ve kullanılmaması gerektiğini unutmayın. $@sadece quot ( "$@") ve liste bağlamında kullanılmalıdır.

for i in "$@" Bir liste bağlamı olarak nitelendirilir, ancak burada konumsal parametreler üzerinde dolaşmak için kanonik, en taşınabilir ve daha basit form şudur:

for i
do something with "$i"
done

Şimdi, ikinciden başlayarak elementlerin üzerinden geçmek için, kanonik ve en taşınabilir yol kullanmaktır shift:

first_arg=$1
shift # short for shift 1
for i
do something with "$i"
done

Daha sonra shift, eskiden olanlar $1listeden çıkarıldı (ama onu kaydettik $first_arg) ve eskiden olanlar $2şimdi içeride $1. Konumsal parametreler 1pozisyona sola kaydırılmıştır ( shift 22'ye kaydırmak için kullanın ). Yani temelde, bizim döngü eskiden ikinci argüman olandan sonuncuya doğru döngü yapıyor.

Ile bash(ve zshve ksh93, ama bu kadar), bir alternatif yapmaktır:

for i in "${@:2}"
do something with "$i"
done

Ancak bunun standart shsözdizimi olmadığına dikkat edin, bu nedenle başlayan bir komut dosyasında kullanılmamalıdır #! /bin/sh -.

İçinde zshveya yashşunları da yapabilirsiniz:

for i in "${@[3,-3]}"
do something with "$i"
done

3. ile 3. son argüman arasında döngü yapmak için.

İçinde zsh, dizi $@olarak da bilinir $argv. Böylece, dizilerin başından veya sonundan ögeler eklemek için şunları da yapabilirsiniz:

argv[1,3]=() # remove the first 3 elements
argv[-3,-1]=()

( shiftAynı zamanda yazılabilir 1=()içinde zsh)

İçinde bash, yalnızca yerleşik olan $@öğelere atanabilir set, böylece uçtan 3 öğe çıkararak şöyle bir şey olur:

set -- "${@:1:$#-3}"

Ve 3. sondan 3. sırasına kadar döngü:

for i in "${@:3:$#-5}"
do something with "$i"
done

POSIXly, son 3 öğesini "$@"açmak için bir döngü kullanmanız gerekir:

n=$(($# - 3))
for arg do
  [ "$n" -gt 0 ] && set -- "$@" "$arg"
  shift
  n=$((n - 1))
done

2
Alternatif (ve çirkin) bash imkanı: dolaylı değişkenler:for ((i=2; i<=$#; i++)); do something with "${!i}"; done
glenn jackman

C ++ ile daha tanıdık olduğum için bu sürüme daha aşina oldum.
user40780

10

Bence sen shiftyapıyı istiyorsun . Bu yeniden adlandırır $2için $1, $3için $2, vs.

Bunun gibi:

shift
for i in "$@"; do
    echo $i
done

For döngüsü içinde bunu nasıl başarabilirim? Teşekkür ederim.
user40780,

1
Siz yapmazsınız - fordöngüye girmeden önce kullanırsınız , sonra normalde $ @ ile döngüden geçirirsiniz. shiftAramadan sonra , $ @ olmalıdırarg2_1 arg2_2 arg2_3...
John

Ancak, bir sorum daha olacak: Diyelim ki $ 1'den $ ($ # - 2) 'ye kadar döngü yapmak istiyorum (yani arg_1 - arg_2 _ # - 1 hariç, arg_2 _ # hariç) Ne yapmalıyım?
user40780,

2

Her zaman mağara adamı yaklaşımı var:

first=1
for i
do
        if [ "$first" ]
        then
                first=
                continue
        fi
        something with "$i"
done

Bu $@(daha sonra kullanmak istersen) bozulmadan kalıyor ve her argüman üzerinde dönüyor, ancak birincisini işlemiyor.


1

Kısaca, bu döngüyü açık bir şekilde indeksleme ile de yazabilirsiniz:

for ((i=2; i<=$#; ++i)); do
  process "${!i}"
done

Bu, ikinci olandan sonuncuya kadar olan tüm argümanları yineler. Bunun yerine son argümanı dışlamak istiyorsanız, bunu basitçe yapın.

for ((i=1; i<=$#-1; ++i)); do
  process "${!i}"
done

ve sadece diğer tüm argümanları almak istiyorsanız,

for ((i=1; i<=$#; i+=2)); do
  process "${!i}"
done

Bunun ardındaki hikaye , argüman sayımı ve değişken dolaylaması ile birlikte, yerleşimin aritmetik versiyonudur .for$#${…}

Güzel bir uygulama, bunu, döngünün içinde verilen bir seçeneğin onu izleyen argümanı alıp almayacağına karar vermek için kullanmanızdır. Varsa , bir sonraki değeri tüketmek için artırma i(örneğin yazma : $((++i))) ve yineleme sırasında bunu atlayın.

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.