Parametre alan bir Bash takma adı oluştur?


1270

CShell () değiştirir. Bu, parametre alan bir takma ad oluşturmanıza olanak tanır. Gösterim şöyle bir şeydi

alias junk="mv \\!* ~/.Trash"

Bash'te bu işe yaramıyor gibi görünüyor. Bash'in çok sayıda kullanışlı özelliğe sahip olduğu göz önüne alındığında, bunun uygulandığını varsayacağım, ancak nasıl olduğunu merak ediyorum.



2
"$1"
Args

Bu soru SO için konu dışıdır. Bu edilmiş UNIX.SE üzerine cevap ve cevap bile rahatsız gerek kalmamasıdır: "Eğer takma olsaydı Örneğin lsiçin ls -la, daha sonra yazarak ls foo barederim gerçekten yürütmek ls -la foo bar. Komut satırında"
Dan Dascalescu

7
bir değişkenin bir ipin ortasına enterpolasyonunda yardımcı olmaz
Franz Sittampalam

1
İşte bu yanlışlığı keşfetmek için kullandığım lil test takma adı ... alias test_args="echo PREFIX --$1-- SUFFIX", çağrıldığında test_args ABCDşu konsol çıktısını verirPREFIX ---- SUFFIX ABCD
jxramos

Yanıtlar:


2122

Bash takma adı parametreleri doğrudan kabul etmez. Bir işlev oluşturmanız gerekecek.

aliasparametreleri kabul etmez, ancak bir işlev tıpkı takma ad gibi çağrılabilir. Örneğin:

myfunction() {
    #do things with parameters like $1 such as
    mv "$1" "$1.bak"
    cp "$2" "$1"
}


myfunction old.conf new.conf #calls `myfunction`

Bu arada, sizin .bashrcve diğer dosyalarınızda tanımlanan Bash işlevleri kabuğunuzda komutlar olarak kullanılabilir. Yani, örneğin, önceki fonksiyonu şöyle çağırabilirsiniz

$ myfunction original.conf my.conf

48
$1Tırnak işaretleri içine almalı mıyım ?
Jürgen Paul

263
Takma ad bildirmeniz bile gerekmez. Sadece işlevi tanımlamak yapacaktır.
dinigo

206
Bir işlevin takma adını değiştiriyorsanız source, .bashrc işlevinizi eklemek işlevi ekler, ancak eski takma adı değiştirmez. Takma adlar işlevlerden daha öncelikli olduğu için takma adı kullanmaya çalışacaktır. Kabuğunuzu kapatıp yeniden açmanız veya başka bir şekilde aramanız gerekir unalias <name>. Belki birilerini boşa harcadığım 5 dakikadan kurtaracağım.
Marty Neal

55
@MartinNeal: Sun'da öğrendiğim zaman kazandıran bir numara sadece aşağıdakileri yapmaktır exec bash: Yeni bir kabuk başlatacak, tıpkı kapatıp tekrar açmış gibi yapılandırmanızı temiz bir şekilde okuyacak, ancak o oturumun ortam değişkeni ayarlarını da koruyacak . Ayrıca, bashbir yığın gibi düşünmek istediğinizde exec olmadan yürütmek yararlı olabilir.
Macneil Shonle

21
@mich - evet, her zaman bash değişkenlerini tırnak içine alır. örn mv "$1" "$1.bak". tırnak işaretleri olmadan, $ 1 "merhaba dünya" olsaydı, mv hello world hello world.bakyerine yürütürdünüz mv "hello world" "hello world.bak".
orion elenzil

208

Yukarıdaki yanıtı hassaslaştırdığınızda, bir kabuk veya .bashrc dosyalarındaki geçici tanımlamalar için daha uygun olan takma adlar için olabildiğince 1 satırlık bir sözdizimi alabilirsiniz:

bash$ myfunction() { mv "$1" "$1.bak" && cp -i "$2" "$1"; }

bash$ myfunction original.conf my.conf

Sağ köşeli ayraçtan önce noktalı virgül unutmayın. Benzer şekilde, asıl soru için:

csh% alias junk="mv \\!* ~/.Trash"

bash$ junk() { mv "$@" ~/.Trash/; }

Veya:

bash$ junk() { for item in "$@" ; do echo "Trashing: $item" ; mv "$item" ~/.Trash/; done; }

3
Ben gelebilir argüman dizisi üzerinden yineleme gösterir gibi bu cevabı tercih. $ 1 ve $ 2 sadece bu özel durumlarda, bu cevap da gösterilmiştir.
philo vivero

16
Değişim mv "$1" "$1.bak"; cp "$2" "$1" içine mv "$1" "$1.bak" && cp "$2" "$1"verilerinizi kaybetmemek için zaman mvderde çalışır (örneğin, dosya sistemi tam).
Henk Langeveld

3
"Sağ köşeli ayraç kapanmadan önce noktalı virgül unutmayın." Birçok kez bu! Teşekkürler :)
Kaushal Modi

İlk braketten sonraki ve son braketten önceki boşluklar da gereklidir.
Bryan Chapel

1
@HenkLangeveld Düşünceleriniz mükemmel bir şekilde doğru olsa da, bir süredir etrafınızda olduğunu gösterir - En son ne zaman "cihazda boş alan kalmadı" hatasıyla karşılaştığımı bilemiyorum ;-). (Artık mutfak tezgahında yer bulamadığımda düzenli olarak kullanıyorum!) Bu günlerde çok sık görünmüyor.
Peter - Monica'yı

124

Soru basitçe yanlış sorulur. Parametreleri alan bir takma ad oluşturmazsınız, çünkü aliaszaten var olan bir şey için ikinci bir ad ekler. OP'nin istediği işlevsellik, functionyeni bir işlev oluşturma komutudur. İşlevin zaten bir adı olduğundan, işlevi diğer ad olarak adlandırmanız gerekmez.

Bence böyle bir şey istiyorsun:

function trash() { mv "$@" ~/.Trash; }

Bu kadar! $ 1, $ 2, $ 3, vb parametrelerini kullanabilir veya tümünü $ @ ile doldurabilirsiniz.


7
Bu cevap her şeyi söylüyor. Bu sayfanın altından okuyabilseydim, biraz zaman kazanmış olurdum.
joe

-1 Bir takma ad ve bir işlev eşdeğer değildir ...echo -e '#!/bin/bash\nshopt -s expand_aliases\nalias asrc='\''echo "${BASH_SOURCE[0]}"'\'' # note the '\''s\nfunction fsrc(){ echo "${BASH_SOURCE[0]}";}'>>file2&&echo -e '#!/bin/bash\n. file2\nalias rl='\''readlink -f'\''\nrl $(asrc)\nrl $(fsrc)'>>file1&&chmod +x file1&&./file1;rm -f file1 file2
Bulanık Mantık

$@Boşluklu dosya adlarını vb. Desteklemek için gerçekten teklif vermelisiniz
Tom Hale

Diğer ad parametrelerinizin olmadığı genel bir açıklama olması gerekiyordu, bunun yerine bir işlev kullanıyorsunuz. Verilen işlev yalnızca orijinal örneğe karşı koymak için bir örnektir. Kişinin genel amaçlı bir çöp işlevi aradığını düşünmüyorum. Ancak, daha iyi kod sunmak amacıyla, cevabı güncelledim.
Evan Langlois

1
@FuzzyLogic - Yorumunuzdaki kodu açmaya çalışırken birkaç dakika geçirdim. Bazı kodları düzgün bir şekilde biçimlendiremeyeceğiniz bir yorumda paketlemek için uğraşmanız gereken (ilginç) bir çaba. Hala tam olarak ne yaptığını veya daha da önemlisi neden (doğru) iddianızı desteklediğini anlamadım.
Joe

110

TL; DR: Bunu yerine yap

Bir komutu kullanmak, bir komutun ortasına argümanlar koymak için bir takma addan çok daha kolay ve daha okunabilir.

$ wrap_args() { echo "before $@ after"; }
$ wrap_args 1 2 3
before 1 2 3 after

Okumaya devam ederseniz, kabuk argümanı işleme hakkında bilmeniz gerekmeyen şeyler öğreneceksiniz. Bilgi tehlikelidir. Karanlık taraf sonsuza dek kaderini kontrol etmeden önce istediğin sonucu al.

açıklama

bashadlar yapmak ama sadece az, argümanları kabul sonuna :

$ alias speak=echo
$ speak hello world
hello world

Üzerinden komutun ortasına argümanlar koymak aliasgerçekten mümkün ama çirkinleşiyor.

Bunu evde denemeyin, çocuklar!

Sınırlamaları atlatmak ve başkalarının söylediklerini yapmak imkansızsa, işte tarif. Saçlarınız çıldırır ve yüzünüz çılgın bilim adamı tarzıyla kaplanırsa beni suçlamayın.

Çözüm, aliasyalnızca sonunda kabul edilen argümanları, onları ortaya yerleştirecek ve daha sonra komutunuzu yürütecek bir sarıcıya iletmektir.

Çözüm 1

Gerçekten kendi başınıza bir işlev kullanmaya karşı çıkıyorsanız, şunları kullanabilirsiniz:

$ alias wrap_args='f(){ echo before "$@" after;  unset -f f; }; f'
$ wrap_args x y z
before x y z after

Sen değiştirebilirsiniz $@ile $1sadece ilk argüman istiyorum.

Açıklama 1

Bu f, bağımsız değişkenlerden geçirilen geçici bir işlev oluşturur ( fen sonunda çağrılan not ). Diğer unset -fad yürütüldükçe işlev tanımını kaldırır, böylece daha sonra takılmaz.

Çözüm 2

Alt kabuk da kullanabilirsiniz:

$ alias wrap_args='sh -c '\''echo before "$@" after'\'' _'

Açıklama 2

Takma ad aşağıdaki gibi bir komut oluşturur:

sh -c 'echo before "$@" after' _

Yorumlar:

  • Yer tutucu _gereklidir, ancak herhangi bir şey olabilir. sh'S olarak ayarlanır $0ve kullanıcı tarafından verilen argümanlardan ilkinin tüketilmemesi için gereklidir. gösteri:

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
    
  • Tek tırnak içindeki tek tırnaklar gereklidir. Çift tırnak işareti ile çalışmayan bir örnek:

    $ sh -c "echo Consumed: $0 Printing: $@" alcohol drunken babble
    Consumed: -bash Printing:
    

    İşte interaktif kabuk en değerleri $0ve $@alıntı çift içine değiştirilir önce o geçirilir sh. İşte kanıt:

    echo "Consumed: $0 Printing: $@"
    Consumed: -bash Printing:
    

    Tek tırnak, bu değişkenlerin etkileşimli kabuk tarafından yorumlanmamasını ve tam anlamıyla iletilmesini sağlar sh -c.

    Çift tırnak kullanabilirsiniz ve \$@en iyi uygulama argümanlarınızı alıntılamaktır (boşluk içerebileceği için) ve \"\$@\"daha çirkin görünür, ancak çılgın saçların giriş için bir önkoşul olduğu bir gizlilik yarışmasını kazanmanıza yardımcı olabilir.


2
çözüm 1 için, tek tırnak kullandığınızdan emin olun ve $ @ civarında \ "kullanmaktan kaçının. İhtiyacınız olursa çok kullanışlı bir teknik. ty.
sgtz

Çözüm 1 benim için çalıştı rdesktop-vrdp istediğim her sunucu için argüman ile sarın.
Hsehdar

Sonunda argüman kabul etmek tam olarak "git checkout {branchname}" yerine basit bir "gc {branchname}" yerine geçmek istediğim şeydir. .Bash_profile içinde sadece eklemek zorunda kaldımalias gc='git checkout'
AbstractVoid

@sgtz neden teklifleri kaldırmak istiyorsun $@? İçlerinde boşluk bulunan dosyalarınız varsa bunlar gereklidir.
Tom Hale

@TomHale Bu biraz dilbilimsel olmakla birlikte, eğer birisi gerçekten bir işlevi kullanmaya karşı çıkıyorsa (neden olursa olsun) çözüm 1 gerçekten yararlı değildir, çünkü kendinize doğrudan bir fonksiyonun tanımını yalnızca yürütme süresine kaydırdığınızı kabul edersiniz takma ad. ikincisi, "bash takma adları argümanları kabul eder, ancak sadece sonunda" daha fazla anlamsaldır: takma adlar, tanım başına kelimelerin dizgilerle değiştirilmesidir. argümanları kabul etmelerine gerek yoktur, ancak ikame yoluyla yürütülen komutlar bunu yapabilir. takma ad bir karakter değişimidir, başka bir şey değildir, daha az bir şey değildir. Hayır?
BUFU

39

Alternatif bir çözüm kullanımı için işaretleyici , "imi" komutu şablonları ve komut yer tutucular kolayca yer imlecin yapmanızı sağlar Geçenlerde oluşturduk bir araç:

komut satırı işaretleyicisi

Çoğu zaman, kabuk işlevlerini kullanıyorum, bu yüzden sık kullanılan komutları komut satırına tekrar tekrar yazmak zorunda değilim. Bu kullanım durumu için işlevlerin kullanılması sorunu, komut sözlüğüme yeni terimler eklemek ve gerçek komutta hangi işlev parametrelerinin bahsettiğini hatırlamak zorunda kalmaktır. Marker amaç bu zihinsel yükü ortadan kaldırmaktır.


14

Tek yapmanız gereken bir takma adın içinde bir işlev yapmaktır:

$ alias mkcd='_mkcd(){ mkdir "$1"; cd "$1";}; _mkcd'

Sen gerekir çünkü tek tırnak olmaz işi "$ 1" çift tırnak koydu.


5
Bu zekice, ama sorunun bir takma ad oluşturmayı belirtmesi dışında, sadece başlangıçta takma adla aynı ada sahip işlevi yapmak için herhangi bir neden var mı?
xaxxon

1
@xaxxon Pek değil, ama bir takma ad kullanmanın en kolay yolu, bir işlev değil.
Ken Tran

1
Bu çalışmıyor. Ubuntu 18'de hata alıyorum bash: syntax error near unexpected token '{mkdir'.
Shital Shah

;işlevin içinde bir iz eksik _mkcdbüyük olasılıkla hata budur.
Ocak'ta Jetchisel

Önce ve sonra boşluk bırakın {ve}
hesham_EE

10

İşte en yaşıyorum benim, var fonksiyonlarının üç örneği ~/.bashrcvardır, esasen bir parametre kabul takma adları:

#Utility required by all below functions.
#/programming/369758/how-to-trim-whitespace-from-bash-variable#comment21953456_3232433
alias trim="sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*\$//g'"

.

:<<COMMENT
    Alias function for recursive deletion, with are-you-sure prompt.

    Example:
        srf /home/myusername/django_files/rest_tutorial/rest_venv/

    Parameter is required, and must be at least one non-whitespace character.

    Short description: Stored in SRF_DESC

    With the following setting, this is *not* added to the history:
        export HISTIGNORE="*rm -r*:srf *"
    - https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash

    See:
    - y/n prompt: https://stackoverflow.com/a/3232082/2736496
    - Alias w/param: https://stackoverflow.com/a/7131683/2736496
COMMENT
#SRF_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
SRF_DESC="srf [path]: Recursive deletion, with y/n prompt\n"
srf()  {
    #Exit if no parameter is provided (if it's the empty string)
        param=$(echo "$1" | trim)
        echo "$param"
        if [ -z "$param" ]  #http://tldp.org/LDP/abs/html/comparison-ops.html
        then
          echo "Required parameter missing. Cancelled"; return
        fi

    #Actual line-breaks required in order to expand the variable.
    #- https://stackoverflow.com/a/4296147/2736496
    read -r -p "About to
    sudo rm -rf \"$param\"
Are you sure? [y/N] " response
    response=${response,,}    # tolower
    if [[ $response =~ ^(yes|y)$ ]]
    then
        sudo rm -rf "$param"
    else
        echo "Cancelled."
    fi
}

.

:<<COMMENT
    Delete item from history based on its line number. No prompt.

    Short description: Stored in HX_DESC

    Examples
        hx 112
        hx 3

    See:
    - https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
COMMENT
#HX_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
HX_DESC="hx [linenum]: Delete history item at line number\n"
hx()  {
    history -d "$1"
}

.

:<<COMMENT
    Deletes all lines from the history that match a search string, with a
    prompt. The history file is then reloaded into memory.

    Short description: Stored in HXF_DESC

    Examples
        hxf "rm -rf"
        hxf ^source

    Parameter is required, and must be at least one non-whitespace character.

    With the following setting, this is *not* added to the history:
        export HISTIGNORE="*hxf *"
    - https://superuser.com/questions/232885/can-you-share-wisdom-on-using-histignore-in-bash

    See:
    - https://unix.stackexchange.com/questions/57924/how-to-delete-commands-in-history-matching-a-given-string
COMMENT
#HXF_DESC: For "aliaf" command (with an 'f'). Must end with a newline.
HXF_DESC="hxf [searchterm]: Delete all history items matching search term, with y/n prompt\n"
hxf()  {
    #Exit if no parameter is provided (if it's the empty string)
        param=$(echo "$1" | trim)
        echo "$param"
        if [ -z "$param" ]  #http://tldp.org/LDP/abs/html/comparison-ops.html
        then
          echo "Required parameter missing. Cancelled"; return
        fi

    read -r -p "About to delete all items from history that match \"$param\". Are you sure? [y/N] " response
    response=${response,,}    # tolower
    if [[ $response =~ ^(yes|y)$ ]]
    then
        #Delete all matched items from the file, and duplicate it to a temp
        #location.
        grep -v "$param" "$HISTFILE" > /tmp/history

        #Clear all items in the current sessions history (in memory). This
        #empties out $HISTFILE.
        history -c

        #Overwrite the actual history file with the temp one.
        mv /tmp/history "$HISTFILE"

        #Now reload it.
        history -r "$HISTFILE"     #Alternative: exec bash
    else
        echo "Cancelled."
    fi
}

Referanslar:


Ha? Bu bir işlev, takma ad değil. Ve referanslarınızdan biri bu soru.
üçlü

2
Hayır, tam olarak bir işlev gibi çalışır. Buradaki cevapların birçoğunun açıkladığı gibi, parametre alan bir takma ad yapamazsınız. Yapabileceğiniz şey, yaptığınız şey olan bir işlev yazmaktır.
3

1
@tripleee Benim bash newbie bakış açısından, yorumunuzu okumadan önce, bunun bir takma ad olduğunu düşündüm (bir tane oluşturmak için alternatif bir yol). Anlayabildiğim kadarıyla tam olarak bir işlev görür. Terminolojiye kapılmış olsam bile , aslında bir parametreyi kabul eden bir takma addır. Sorunu görmüyorum. Bu sorunun diğer cevabının bağlantısını açıkladım. Bunu yaratmama yardımcı oldu.
aliteralmind

1
Belki de bu özellikle "bir parametreyi kabul eden bir bash takma adı" sorusuna cevap vermez, çünkü şimdi bunun mümkün olmadığını anlıyorum, ancak kesinlikle etkili bir şekilde cevaplıyor. Burada ne eksik?
aliteralmind

2
Burada bazı gerçekten iyi örnekler ve güzel yorumlanmış kod. Bu sayfaya gelen insanlar için büyük bir yardım.
00'de chim

9

Bash takma adı kesinlikle parametreleri kabul eder. Uygulama adını parametre olarak kabul eden yeni bir reaksiyon uygulaması oluşturmak için bir takma ad ekledim. İşte benim sürecim:

Nano'da düzenlemek için bash_profile dosyasını açın

nano /.bash_profile

Takma adlarınızı her satıra bir tane ekleyin:

alias gita='git add .'
alias gitc='git commit -m "$@"'
alias gitpom='git push origin master'
alias creact='npx create-react-app "$@"'

not: "$ @", "creact my-new-app" gibi aktarılan parametreleri kabul eder

Nano düzenleyiciyi kaydet ve çık

yazmak için ctrl + o (enter tuşuna basın); çıkmak için ctrl + x

Terminalden .bash_profile içindeki yeni diğer adları kullanmasını isteyin

source /.bash_profile

Bu kadar! Artık yeni takma adlarınızı kullanabilirsiniz


6

Not: Fikrin açık olmaması durumunda, takma adlar takma adlardan başka bir şey için kullanmak kötü bir fikirdir, ilki 'takma addaki işlev' ve ikincisi 'okunması zor yönlendirme / kaynak'. Ayrıca, kusurları vardır (ki bunun açık olacağını düşündüm , ancak kafanız karıştıysa: Aslında bunların her yerde kullanılması anlamına gelmez ...)

.................................................. .................................................. ............................................

Bunu daha önce cevapladım ve geçmişte hep böyle oldu:

alias foo='__foo() { unset -f $0; echo "arg1 for foo=$1"; }; __foo()'

işlevlerin birlikte kullanılmasından kaçınmıyorsanız, iyi ve iyi. bu durumda bash'ın metni yeniden yönlendirme yeteneğinden yararlanabilirsiniz:

alias bar='cat <<< '\''echo arg1 for bar=$1'\'' | source /dev/stdin'

Her ikisi de yaklaşık aynı uzunlukta birkaç karakter verir veya alır.

Gerçek vurucu zaman farkıdır, 'işlev yöntemi' ve 'yeniden yönlendirme kaynaklı' yöntemi olmak alt olmak en. Bu teoriyi kanıtlamak için zamanlama kendisi için konuşur:

arg1 for foo=FOOVALUE
 real 0m0.011s user 0m0.004s sys 0m0.008s  # <--time spent in foo
 real 0m0.000s user 0m0.000s sys 0m0.000s  # <--time spent in bar
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.010s user 0m0.004s sys 0m0.004s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.011s user 0m0.000s sys 0m0.012s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.012s user 0m0.004s sys 0m0.004s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE
ubuntu@localhost /usr/bin# time foo FOOVALUE; time bar BARVALUE
arg1 for foo=FOOVALUE
 real 0m0.010s user 0m0.008s sys 0m0.004s
 real 0m0.000s user 0m0.000s sys 0m0.000s
arg1 for bar=BARVALUE

Bu, rastgele aralıklarla yapılan yaklaşık 200 sonucun alt kısmıdır. İşlev oluşturma / yok etme, yeniden yönlendirmeden daha fazla zaman alıyor gibi görünüyor. Umarım bu, gelecekteki ziyaretçilerin bu soruya yardımcı olacaktır (kendime saklamak istemiyordu).


2
Bir işlevi tanımlayan bir takma ada sahip olmak, o işlevi çalıştırmak sadece saçmadır. Sadece bir işlev yazın. Neredeyse her amaç için takma adların yerini kabuk işlevleri alır.
geirha

deneyebileceğiniz her şeyi okumadığınız takdirde, işlev yöntemini kullanmanın neden ilk etapta hiç iyi olmadığını ve dahası, hiç saçma olmadığını gösterdim. Kişisel olarak beğenmediğiniz için yayınlamayı ve indirmeyi durdurun ... veya en azından geçerli bir açıklama yapın. İsim arama ilk
fikir

1
İkincisinin (çubuk takma adı) birkaç yan etkisi vardır. İlk olarak komut stdin kullanamaz. İkincisi, takma addan sonra hiçbir argüman sağlanmazsa, kabuğun aldığı argümanlar ne olursa olsun geçer. Bir işlevi kullanmak tüm bu yan etkileri önler. (Ayrıca işe yaramaz kedi kullanımı).
geirha

2
hey ben bunu yapmak için iyi bir fikir olduğunu asla söylemedim, ben sadece bunun hakkında gitmek için başka yollar olduğunu söyledi - burada ana fikir takma işlevler kullanmamalısınız çünkü onlar karmaşık bile daha yavaş yönlendirme, bunun açık olacağını düşündüm ama sanırım herkes için hecelemeliyim (bu da ilk etapta yaptıysam yazı çok şişkin olduğu için bağırdım)
osirisgothra

1
Çubuğun zamanlamaları hepsi 0 olduğundan, kabuğun bunu doğru bir şekilde zamanlamadığından şüphelenirim. Komut çalıştırılmadan önce zaman mesajının yazdırıldığına dikkat edin ? Ergo, hiçbir şey zamanlamıyor ve sonra çubuk yapıyor, bu yüzden hiç çubuk ölçmüyorsunuz. Daha karmaşık bir şey yapın ya da barda büyük bir döngü yapın, böylece hiçbir şeyi
Evan Langlois

6

Tüm parametreleri bir veya iki veya başka bir sabit kodlanmış miktara değil, bir işleve uygulamak için genel bir yol arıyorsanız, bunu şu şekilde yapabilirsiniz:

#!/usr/bin/env bash

# you would want to `source` this file, maybe in your .bash_profile?
function runjar_fn(){
    java -jar myjar.jar "$@";
}

alias runjar=runjar_fn;

Yani yukarıdaki örnekte runjar, diğer parametreleri çalıştığımda tüm parametreleri iletiyorum.

Örneğin, eğer ben yaptım runjar hi thereaslında çalışan sona erecekti java -jar myjar.jar hi there. Eğer runjar one two threeyapsaydım koşardı java -jar myjar.jar one two three.

Bu $@tabanlı çözümü seviyorum çünkü herhangi bir sayıda param ile çalışıyor.


4
neden sadece runjarbir işleve takma ad yapmak yerine işlevi adlandırmıyorsunuz? Gereksiz derecede karmaşık görünüyor!
Evan Langlois

@EvanLanglois işlevleri bash dosyalarında otomatik olarak açılır alias(veya nesnelerin özelliklerinin aktarılması alias)? evet ise, o zaman sadece bunu bilmiyordum
Micah

Ne demek istediğini anlamıyorum. Takma ad, kişi veya işlev olsun, başka bir addır. Yani, bir işlev yaptınız, sonra işlev için ikinci bir isim yaptınız. Takma ad hakkında özel bir şey yok, sadece ikinci bir isim ve gerekli değil. Komut satırına yazdıklarınız iç veya dış işlevler olabilir, bu nedenle "işlev" diğer ad değil yeni bir komut yapar.
Evan Langlois

4
Bu anlamsız. İle aynı alias runjar='java -jar myjar.jar'. Takma adlar yalnızca sonunda kabul edilen argümanları kabul eder.
Tom Hale

6

Bir takma adın ortasına bir parametre ekleyemeyeceğinizi söyleyen herkese saygıyla test ettim ve işe yaradığını gördüm.

takma ad mycommand = "python3" $ 1 "script.py --folderoutput SONUÇLAR /"

mycommand foobar'ı çalıştırdığımda, komutu uzunca yazmışım gibi çalıştı.


Kesinlikle, takma ad parametreleri alabilirsiniz, ben bunu kullanarak
yaşlarım

Benim için çalışmıyor: alias myalias="echo 1 "$1" 3"; myalias 2verir:1 3 2
dirdi

4

Keyfî argümanları yeniden konumlandırmak için bir mekanizmaya sahip olmayan bash takma adı sorununa genel bir çözüm istemenin meşru teknik nedenleri vardır. Bunun bir nedeni, yürütmek istediğiniz komutun, bir işlev yürütmekten kaynaklanan ortamdaki değişikliklerden olumsuz etkilenmesi. Toplamda diğer durumlarda, fonksiyonlar kullanılmalıdır.

Son zamanlarda beni buna bir çözüm denemeye zorlayan şey, değişkenlerin ve fonksiyonların tanımlarını yazdırmak için bazı kısaltılmış komutlar oluşturmak istememdi. Bu yüzden bu amaçla bazı fonksiyonlar yazdım. Ancak, bir işlev çağrısının kendisi tarafından değiştirilen (veya değiştirilebilen) bazı değişkenler vardır. Aralarında:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

Değişken hatalarını yazdırmak için (işlevde) kullandığım temel komut. set komutunun çıktı formunda:

sv () { set | grep --color=never -- "^$1=.*"; }

Örneğin:

> V=voodoo
sv V
V=voodoo

Sorun: Bu, yukarıda belirtilen değişkenlerin tanımlarını geçerli bağlamda oldukları gibi yazdırmaz , örneğin, etkileşimli bir kabuk isteminde (veya herhangi bir işlev çağrısında bulunmuyorsa), FUNCNAME tanımlanmamıştır. Ama işlevim bana yanlış bilgiyi söylüyor:

> sv FUNCNAME
FUNCNAME=([0]="sv")

Geldiğim bir çözüm, bu konudaki diğer yayınlarda başkaları tarafından belirtildi. Değişken hatalarını yazdırmak için bu özel komut ve yalnızca bir bağımsız değişken gerektirir, bunu yaptım:

alias asv='(grep -- "^$(cat -)=.*" <(set)) <<<'

Bu da doğru çıktıyı (yok) ve sonuç durumunu (yanlış) verir:

> asv FUNCNAME
> echo $?
1

Ancak, yine de rastgele sayıda argüman için çalışan bir çözüm bulmaya zorlandım.

Bash Takma Adlı Komuta Keyfi Argüman Aktarmaya Genel Bir Çözüm:

# (I put this code in a file "alias-arg.sh"):

# cmd [arg1 ...] – an experimental command that optionally takes args,
# which are printed as "cmd(arg1 ...)"
#
# Also sets global variable "CMD_DONE" to "true".
#
cmd () { echo "cmd($@)"; declare -g CMD_DONE=true; }

# Now set up an alias "ac2" that passes to cmd two arguments placed
# after the alias, but passes them to cmd with their order reversed:
#
# ac2 cmd_arg2 cmd_arg1 – calls "cmd" as: "cmd cmd_arg1 cmd_arg2"
#
alias ac2='
    # Set up cmd to be execed after f() finishes:
    #
    trap '\''cmd "${CMD_ARGV[1]}" "${CMD_ARGV[0]}"'\'' SIGUSR1;
    #        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    #       (^This is the actually execed command^)
    #
    # f [arg0 arg1 ...] – acquires args and sets up trap to run cmd:
    f () {
        declare -ag CMD_ARGV=("$@");  # array to give args to cmd
        kill -SIGUSR1 $$;             # this causes cmd to be run
        trap SIGUSR1;                 # unset the trap for SIGUSR1
        unset CMD_ARGV;               # clean up env...
        unset f;                      # incl. this function!
    };
    f'  # Finally, exec f, which will receive the args following "ac2".

Örneğin:

> . alias-arg.sh
> ac2 one two
cmd(two one)
>
> # Check to see that command run via trap affects this environment:
> asv CMD_DONE
CMD_DONE=true

Bu çözümle ilgili güzel bir şey, konumsal parametreleri (argümanları) komutlara işlemek için kullanılan tüm özel hilelerin, yakalanan komutu oluştururken işe yaramasıdır. Tek fark, dizi sözdiziminin kullanılması gerektiğidir.

Örneğin,

"$ @" İstiyorsanız, "$ {CMD_ARGV [@]}" kullanın.

"$ #" İstiyorsanız, "$ {# CMD_ARGV [@]}" kullanın.

Vb.


3

Bir keresinde eğlenceli bir proje yaptım ve hala kullanıyorum. cpKomut coz ile dosyaları kopyalarken bazı animasyonlar cpgösteriyor, hiçbir şey göstermiyor ve sinir bozucu. Bu takma adı yaptım

alias cp="~/SCR/spiner cp"

Ve bu spiner senaryosu

#!/bin/bash

#Set timer
T=$(date +%s)

#Add some color
. ~/SCR/color

#Animation sprites
sprite=( "(* )  ( *)" " (* )( *) " " ( *)(* ) " "( *)  (* )" "(* )  ( *)" )

#Print empty line and hide cursor
printf "\n${COF}"

#Exit function
function bye { printf "${CON}"; [ -e /proc/$pid ] && kill -9 $pid; exit; }; trap bye INT

#Run our command and get its pid
"$@" & pid=$!

#Waiting animation
i=0; while [ -e /proc/$pid ]; do sleep 0.1

    printf "\r${GRN}Please wait... ${YLW}${sprite[$i]}${DEF}"
    ((i++)); [[ $i = ${#sprite[@]} ]] && i=0

done

#Print time and exit
T=$(($(date +%s)-$T))
printf "\n\nTime taken: $(date -u -d @${T} +'%T')\n"

bye

Şuna benziyor

resim açıklamasını buraya girin

Döngü animasyon)

resim açıklamasını buraya girin


2

Parametreleri almak için işlevleri kullanmalısınız!

Ancak $ @ takma adın yürütülmesi yerine takma ad oluşturulurken ve $ 'dan kaçmak için yorumlanmaz. Bu sorunu nasıl çözerim?

Bu sorundan kurtulmak için bir takma ad yerine kabuk işlevini kullanmanız gerekir. Foo'yu aşağıdaki gibi tanımlayabilirsiniz:

function foo() { /path/to/command "$@" ;}

VEYA

foo() { /path/to/command "$@" ;}

Son olarak, aşağıdaki sözdizimini kullanarak foo () yönteminizi çağırın:

foo arg1 arg2 argN

Foo () öğenizi ~/.bash_profileveya ~/.zshrcdosyanıza eklediğinizden emin olun .

Senin durumunda, bu işe yarayacak

function trash() { mv $@ ~/.Trash; }

Fikrini anlamıyorum. Bence argümanlar yorumlandığında önemli değil. Aliase sonunda istediğiniz kadar parametre kabul eder.
Timo

Ancak bunu işlevlerle yapmak daha iyidir. Takma adlar bunun için tasarlanmamıştır.
Ahmad Awais

1

Fonksiyonlar gerçekten de hemen hemen her zaman cevaptır, çünkü man sayfasından bu alıntıyla çokça katkıda bulunulmuş ve onaylanmıştır: "Neredeyse her amaç için, takma adların yerini kabuk fonksiyonları alır."

Tamlık için ve bu yararlı olabileceğinden (marjinal olarak daha hafif bir sözdizimi), parametre (ler) takma adı takip ettiğinde, hala kullanılabilecekleri belirtilebilir (bu, OP'nin gereksinimini karşılamasa da). Bu muhtemelen bir örnekle gösterilmesi en kolay yöntemdir:

alias ssh_disc='ssh -O stop'

ssh_disc myhostbeklediğim gibi genişleyen gibi bir şey yazmamı sağlar :ssh -O stop myhost

Bu, karmaşık argümanlar alan komutlar için yararlı olabilir (hafızam artık kullanacağı şey değil ...)


1

Hem işlevler hem de takma adlar, diğerleri burada gösterildiği gibi parametreleri kullanabilir. Ayrıca, diğer birkaç hususu belirtmek istiyorum:

1. fonksiyonu kendi kapsamında çalışır, takma ad kapsamı

Bir şeyi gizlemeniz veya göstermeniz gereken durumlarda bu farkı bilmek faydalı olabilir. Ayrıca, bir işlevin kapsülleme için daha iyi bir seçim olduğunu gösterir.

function tfunc(){
    GlobalFromFunc="Global From Func" # Function set global variable by default
    local FromFunc="onetwothree from func" # Set a local variable

}

alias talias='local LocalFromAlias="Local from Alias";  GlobalFromAlias="Global From Alias" # Cant hide a variable with local here '
# Test variables set by tfunc
tfunc # call tfunc
echo $GlobalFromFunc # This is visible
echo $LocalFromFunc # This is not visible
# Test variables set by talias
# call talias
talias
echo $GlobalFromAlias # This is invisible
echo $LocalFromAlias # This variable is unset and unusable 

Çıktı:

bash-3.2$     # Test variables set by tfunc
bash-3.2$     tfunc # call tfunc
bash-3.2$     echo $GlobalFromFunc # This is visible
Global From Func
bash-3.2$     echo $LocalFromFunc # This is not visible

bash-3.2$     # Test variables set by talias
bash-3.2$     # call talias
bash-3.2$     talias
bash: local: can only be used in a function
bash-3.2$     echo $GlobalFromAlias # This is invisible
Global From Alias
bash-3.2$ echo $LocalFromAlias # This variable is unset and unusable

2. sarıcı komut dosyası daha iyi bir seçimdir

Birkaç kez, kullanıcı adları veya çok kullanıcılı ortam aracılığıyla oturum açarkenssh veya bunları değiştirirken bir takma ad veya işlev bulunamamıştır . Nokta dosyalarının kaynaklandığı ipuçları ve püf noktaları veya takma adla bu ilginç olanı vardır: alias sd='sudo 'bu sonraki takma adın alias install='sd apt-get install'beklendiği gibi çalışmasına izin verin (ekstra alanı fark edin sd='sudo '). Ancak, bir sarıcı komut dosyası, bu gibi durumlarda bir işlev veya takma addan daha iyi çalışır. Bir sarıcı komut dosyası ile ana avantajı, bir işlev / takma adın kullanılabilir hale getirilmesinden önce kaynaklanması gereken amaçlanan yol (ör. / Usr / loca / bin /) için görünür / yürütülebilir olmasıdır. Örneğin, için ~ / .bash_profile veya ~ / .bashrc içine bir işlev koyarsınız bash, ancak daha sonra başka bir kabuğa geçersiniz (ör.zsh) işlev artık görünmez. Şüphe duyduğunuzda, bir sarıcı komut dosyası her zaman en güvenilir ve taşınabilir çözümdür.


1
Sizce işlev sürümü neden çalışmıyor?
tripleee

@tripleee. Daha okunabilir hale getirmek için yayını düzenledim. "1. takma ad çalışır, işlev ..." başlığı altında bir işlev sürümünün neden çalışmadığını gösterdim. Ve belki de soruyu doğrudan cevaplamak için işlev, takma adın olmadığı yeni bir kapsam sunar.
biocyberman

Bunun işe yaramadığını söylüyorsun ama sana inanmıyorum. sourcebir fonksiyonda gayet iyi çalışıyor.
üçlü

1
f () { source /tmp/nst; }tam olarak beklediğim şeyi yapıyor. Belki PATHde yanılıyorsunuz, bu yüzden yanlış activateya da bir şey yapıyor; ancak sourcebir işlevden çalıştırmak iyi çalışır.
üçlü

1
BTW, re: functiontanımınızdaki anahtar kelimeyi kullanarak , bkz. Wiki.bash-hackers.org/scripting/obsolete - function funcname {POSIX öncesi kabuklarla geriye dönük uyumluluk için eski ksh sözdizimi destekleri funcname() {, resmi POSIX standardında sözdizimi. function funcname() {eski ksh ile uyumlu olmayan veya POSIX sh ile uyumlu olmayan ve bu nedenle en iyi kaçınılmış olan ikisinin bir yanlıştır .
Charles Duffy

1

İşte örnek:

alias gcommit='function _f() { git add -A; git commit -m "$1"; } ; _f'

Çok önemli:

  1. {Önce ve sonra bir boşluk var }.
  2. Bir vardır ;sırayla her komutun ardından. Son komuttan sonra bunu unutursanız, >bunun yerine istem görürsünüz !
  3. Argüman şu şekilde tırnak işaretleri içine alınır: "$1"

2
Bir işlev için bir diğer ad oluşturmanıza gerek yoktur, sadece işlevi doğrudan kullanın.
user3439894

1

Zaten başkaları tarafından işaret edildiği gibi, bir işlevi kullanmak en iyi uygulama olarak düşünülmelidir.

Bununla birlikte, işte başka bir yaklaşım, kaldıraç xargs:

alias junk="xargs -I "{}" -- mv "{}" "~/.Trash" <<< "

Bunun, akışların yeniden yönlendirilmesiyle ilgili yan etkileri olduğunu unutmayın.


0

Hiçbir şey yapmanız gerekmez, takma ad bunu otomatik olarak yapar.

Örneğin, git pull origin master parametresini yapmak istiyorsanız, aşağıdaki gibi bir takma ad oluşturabilirim:

alias gpull = 'git pull origin '

ve gerçekten çağırırken, bir parametre olarak 'master' (şube adı) iletebilirsiniz, şöyle:

gpull master
//or any other branch
gpull mybranch

Bu soruya cevap vermez, çünkü argüman serbestçe yerleştirilemez, sadece sonunda.
dirdi
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.