2011-05-25 22 views
5

Bu soru 3 bölümden oluşur ve her yalnız kolaydır, ancak birlikte kombine (en azından benim için) önemsiz değil :) bağımsız değişkenler olarak almalı ne senaryo yazmaya ihtiyacınız Kabuk betiği argümanlarında "-" nasıl kullanılır?

:

  1. biri

Örnekler komutu için başka komuta dosyaların

  • listesini
  • çeşitli argümanları isim:

    vb. Ben komut komut için argümanlar nelerdir

  • ne

    • ayırt ihtiyaç nedense senaryom İçinde

    • dosyaları

  • yüzden muhtemelen en nelerdir Standart yollara aşağıdaki örnekleri yazın:

    ./my_script head -100 -- a.txt b.txt ./xxx/*.txt 
    ./my_script sed -n 's/xxx/aaa/' -- *.txt 
    

    Soru1: Daha iyi bir çözüm var mı? ./my_script (ilk denemede) içerisinde

    işlem: filenamesspaces içeren zaman

    command="$1";shift 
    args=`echo $* | sed 's/--.*//'` 
    filenames=`echo $* | sed 's/.*--//'` 
    
    #... some additional processing ... 
    
    "$command" "$args" $filenames #execute the command with args and files 
    

    Bu çözelti başarısız olur ve/veya '-', ör
    /bazı -/yol/daha/salakça dosya name.txt

    Soru 2: Düzgün daha sonra yapmak üzere $command onun $args ve $filenames olsun nasıl?

    Soru3: - Aşağıdaki yürütme stiline nasıl ulaşılır?

    echo $filenames | $command $args #but want one filename = one line (like ls -1) 
    

    Güzel kabuk çözümü var mı, yoksa örneğin perl?

    +1

    :

    böyle bir şey olacağını birlikte koyun. 1. neden back-tics kullanmalı?Bunlar, kullanım dışıdır ve Solaris ya da AIX üzerinde çok fazla çalışma yapmayı beklemediğiniz sürece, gerekli değildir. $ (Cmd) kullanın! 2. (sorunuza daha fazla), getopt ve getopts (kabuk için) okuyun. Burada çok sayıda örnek gördüm, en az bir tane ayrıntılı. While gibi bir şeyle birleştiğinde (($ #> 0)) processArgs; vardiya; bitti yardım eder. 3. vaka ifadelerini kullanmayı düşünün. '-' için onlardan kaçmak ya da alıntılamak ya da [-] [-] gibi bir sınıfa dönüştürmek zorunda kalabilirsiniz. – shellter

    cevap

    6

    Her şeyden önce, bir komut ve dosya adları listesi içeren bir komut dosyası yazmaya çalıştığınız ve sırayla her dosya adına komutu çalıştıracağınız anlaşılıyor. Bu bash bir çizgide yapılabilir:

     
    $ for file in a.txt b.txt ./xxx/*.txt;do head -100 "$file";done 
    $ for file in *.txt; do sed -n 's/xxx/aaa/' "$file";done 
    

    Ancak, belki de senin niyet yüzden beni tek tek cevaplayabilir yanlış yorumlanabilir ettik. "-" kullanmak yerine

    (zaten farklı bir anlamı olan), aşağıdaki sözdizimi bana daha uygun geliyorsa:

     
    ./my_script -c "head -100" a.txt b.txt ./xxx/*.txt 
    ./my_script -c "sed -n 's/xxx/aaa/'" *.txt 
    

    , bash bağımsız ayıklamak kullanmak için getopts:

    SCRIPT=$0 
    
    while getopts "c:" opt; do 
        case $opt in 
         c) 
          command=$OPTARG 
          ;; 
        esac 
    done 
    
    shift $((OPTIND-1)) 
    
    if [ -z "$command" ] || [ -z "$*" ]; then 
        echo "Usage: $SCRIPT -c <command> file [file..]" 
        exit 
    fi 
    
    kalan argümanlar her biri için bir komut çalıştırmak istiyorsanız

    , bu şekilde görünecektir:

    for target in "[email protected]";do 
        eval $command \"$target\" 
    done 
    

    Eğer STDIN'den dosya okumak istiyorsanız, bu gibi daha görünecektir:

    while read target; do 
        eval $command \"$target\" 
    done 
    
    +0

    @ TomShaw: İlk güzel yazı. Son kod bloğu için, belki de döngünün iç kısmını 'eval' ile öneklemek istersiniz. Ağır listeyi yaptığınız için teşekkürler. ;-) – shellter

    +0

    @shellter: Geri bildiriminiz için teşekkürler! –

    +0

    @ jm666: Bu güncellenmiş sürüm şimdi boşlukları işlemelidir. –

    0

    Soru 1

    Sana keyfi komutlar için yapmanız gerekir en azından değilse, öyle düşünmüyorum.

    Soru 3

    command=$1 
    shift 
    while [ $1 != '--' ]; do 
        args="$args $1" 
        shift 
    done 
    shift 
    while [ -n "$1" ]; do 
        echo "$1" 
        shift 
    done | $command $args 
    

    Soru 2

    Bu nasıl soru 3 farkı nedir?

    +0

    echo $ dosya adları | sed - dosya adı boşluk içeriyorsa kesilir. Örneğin. echo "file1.txt" "spaces2 with spaces.txt" - bu yüzden soruyor - benim 1. denemem yanlış. – jm666

    +0

    aah Anladım, cevabımı düzenledim –

    3

    [email protected] değişken, grup parametreleri mümkün olacak alıntı zaman olması gerektiği gibi:

    for parameter in "[email protected]" 
    do 
        echo "The parameter is '$parameter'" 
    done 
    

    verilirse:

    head -100 test this "File name" out 
    

    yazdırmak Will

    the parameter is 'head' 
    the parameter is '-100' 
    the parameter is 'test' 
    the parameter is 'this' 
    the parameter is 'File name' 
    the parameter is 'out' 
    

    Şimdi yapmanız gereken tek şey, döngüyü ayrıştırmak. Bazı çok basit kuralları kullanabilirsiniz:

    1. ilk parametre her zaman bir çizgi ile başlamış izleyin
    2. parametrelerdir parametreler sonra
    3. dosya adıdır "-" veya bir kez doesn' t "-" ile başlayalım, gerisi tüm dosya isimleridir.

    Sen parametresinde ilk karakteri bu kullanarak bir çizgi olup olmadığını görmek için kontrol edebilirsiniz:

    if [[ "x${parameter}" == "x${parameter#-}" ]] 
    

    önce bu sözdizimi görmediyseniz, bu sol filtre bu. #, değişken adının iki bölümünü ayırır. İlk kısım değişkenin adıdır ve ikincisi kesilecek glob filtresidir (normal ifade değil). Bu durumda, tek bir çizgi. Bu ifade doğru olmadığı sürece, bir parametreniz olduğunu biliyorsunuz. BTW, x bu durumda gerekli olabilir veya olmayabilir. Bir testi çalıştırdığınızda ve içinde bir çizgi olan bir dizginiz olduğunda, test, testin bir parametresi için değil, değer için hata yapabilir. Bu doğru dürüst cevap için bir süre alacağını

    parameterFlag="" 
    for parameter in "[email protected]"  #Quotes are important! 
    do 
        if [[ "x${parameter}" == "x${parameter#-}" ]] 
        then 
         parameterFlag="Tripped!" 
        fi 
        if [[ "x${parameter}" == "x--" ]] 
        then 
         print "Parameter \"$parameter\" ends the parameter list" 
         parameterFlag="TRIPPED!" 
        fi 
        if [ -n $parameterFlag ] 
        then 
         print "\"$parameter\" is a file" 
        else 
         echo "The parameter \"$parameter\" is a parameter" 
        fi 
    done 
    
    +0

    'x' hack sadece antik kabuklar için gereklidir. Lütfen kullanmayın, kodu çirkin kılar. – nyuszika7h

    +0

    @ nyuszika7h, ... iyi - orada, modern kabuklarda da ihtiyaç duyulabilecek bazı köşe durumları var, fakat bu durumlar sadece [] 'de değil [[]]' de ve "test" durumunda üç argümandan daha fazla iletilir (böylece, -a veya -o kullanıldığında) ... POSIX'in en son sürümünün neden kullanımdan kaldırılmadığını açıklamasının bir parçası. –

    İlgili konular