Membuat alias Bash yang menggunakan parameter?

1273

Saya dulu menggunakan CShell (), yang memungkinkan Anda membuat alias yang mengambil parameter. Notasi itu seperti sesuatu

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

Di Bash, ini sepertinya tidak berhasil. Mengingat bahwa Bash memiliki banyak fitur yang berguna, saya akan berasumsi bahwa yang ini telah diterapkan tetapi saya bertanya-tanya bagaimana caranya.

Halo
sumber
2
Pastikan Anda menggunakan tanda kutip di sekitar argumen"$1"
Christophe Roussy
Pertanyaan ini di luar topik untuk SO. Hal itu dijawab pada UNIX.SE , dan jawabannya adalah bahwa Anda bahkan tidak perlu repot-repot: "Misalnya, jika Anda adalah untuk alias lsuntuk ls -la, kemudian mengetik ls foo barakan benar-benar mengeksekusi ls -la foo bar. Pada baris perintah"
Dan Dascalescu
7
itu tidak akan membantu dengan interpolasi variabel ke tengah-tengah string
Franz Sittampalam
1
Inilah tes lil alias yang saya gunakan untuk menemukan kesalahan ini ... alias test_args="echo PREFIX --$1-- SUFFIX", yang ketika dipanggil dengan test_args ABCDmenghasilkan keluaran konsol berikutPREFIX ---- SUFFIX ABCD
jxramos

Jawaban:

2126

Bash alias tidak langsung menerima parameter. Anda harus membuat fungsi.

aliastidak menerima parameter tetapi fungsi dapat dipanggil seperti alias. Sebagai contoh:

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


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

Omong-omong, fungsi Bash yang ditentukan dalam .bashrcfile Anda dan lainnya tersedia sebagai perintah di dalam shell Anda. Jadi misalnya Anda dapat memanggil fungsi sebelumnya seperti ini

$ myfunction original.conf my.conf
arunkumar
sumber
48
Haruskah saya membungkus $1kutipan?
Jürgen Paul
263
Anda bahkan tidak perlu mendeklarasikan alias. Hanya mendefinisikan fungsi akan dilakukan.
dinigo
207
Jika Anda mengubah alias ke suatu fungsi, sourceing .bashrc Anda akan menambahkan fungsi tersebut tetapi itu tidak akan menyamakan alias yang lama. Karena alias adalah preseden yang lebih tinggi daripada fungsi, alias akan mencoba menggunakan alias. Anda harus menutup dan membuka kembali shell Anda, atau panggil unalias <name>. Mungkin saya akan menyelamatkan seseorang selama 5 menit yang saya sia-siakan.
Marty Neal
56
@ MartinNeal: Satu trik menghemat waktu yang saya pelajari di Sun adalah dengan melakukan exec bash: Ini akan memulai shell baru, memberi Anda bacaan bersih tentang konfigurasi Anda, sama seperti jika Anda menutup dan membuka kembali, tetapi menjaga pengaturan variabel lingkungan sesi itu juga . Juga, mengeksekusi bashtanpa eksekutif dapat berguna ketika Anda ingin menangani berpikir seperti tumpukan.
Macneil Shonle
21
@mich - ya, selalu berikan variabel bash dalam tanda kutip. mis mv "$1" "$1.bak". tanpa tanda kutip, jika $ 1 adalah "hello world", Anda akan mengeksekusi mv hello world hello world.bakbukan mv "hello world" "hello world.bak".
orion elenzil
208

Menyempurnakan jawaban di atas, Anda bisa mendapatkan sintaks 1 baris seperti yang Anda bisa untuk alias, yang lebih nyaman untuk definisi ad-hoc dalam file shell atau .bashrc:

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

bash$ myfunction original.conf my.conf

Jangan lupa tanda titik koma sebelum tanda kurung tutup. Demikian pula, untuk pertanyaan aktual:

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

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

Atau:

bash$ junk() { for item in "$@" ; do echo "Trashing: $item" ; mv "$item" ~/.Trash/; done; }
Mike Gleason
sumber
3
Saya lebih suka jawaban ini, karena menunjukkan iterasi melalui berbagai argumen yang mungkin masuk. $ 1 dan $ 2 hanya kasus khusus, yang juga diilustrasikan dalam jawaban ini.
philo vivero
16
Ubah mv "$1" "$1.bak"; cp "$2" "$1" menjadi mv "$1" "$1.bak" && cp "$2" "$1"untuk tidak kehilangan data Anda ketika mvmengalami masalah (misalnya, sistem file penuh).
Henk Langeveld
3
"Jangan lupa titik koma sebelum tanda kurung tutup." Banyak kali ini! Terima kasih :)
Kaushal Modi
Dan spasi setelah braket pertama dan sebelum braket terakhir juga diperlukan.
Kapel Bryan
1
@HenkLangeveld Sementara komentar Anda sangat benar itu menunjukkan bahwa Anda telah ada untuk sementara waktu - saya tidak akan tahu kapan terakhir kali saya menemukan kesalahan "tidak ada ruang yang tersisa pada perangkat" ;-). (Saya menggunakannya secara teratur meskipun ketika saya tidak menemukan ruang di meja dapur lagi!) Sepertinya tidak sering terjadi hari ini.
Peter - Reinstate Monica
124

Pertanyaannya adalah salah. Anda tidak membuat alias yang mengambil parameter karena aliashanya menambahkan nama kedua untuk sesuatu yang sudah ada. Fungsionalitas yang diinginkan OP adalah functionperintah untuk membuat fungsi baru. Anda tidak perlu alias fungsi karena fungsi sudah memiliki nama.

Saya pikir Anda menginginkan sesuatu seperti ini:

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

Itu dia! Anda dapat menggunakan parameter $ 1, $ 2, $ 3, dll, atau isi semuanya dengan $ @

Evan Langlois
sumber
7
Jawaban ini mengatakan semuanya. Jika saya membaca dari bagian bawah halaman ini, saya akan menghemat waktu.
joe
-1 Sebuah alias dan fungsi tidak setara ...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
Fuzzy Logic
Anda harus mengutip $@untuk mendukung nama file dengan spasi, dll.
Tom Hale
Seharusnya penjelasan umum bahwa Anda tidak memiliki parameter alias, Anda menggunakan fungsi saja. Fungsi yang diberikan hanyalah contoh untuk melawan contoh asli. Saya tidak berpikir orang itu mencari fungsi sampah tujuan umum. Namun, demi menyajikan kode yang lebih baik, saya telah memperbarui jawabannya.
Evan Langlois
1
@ FuzzyLogic - Saya menghabiskan beberapa menit mencoba membongkar kode dalam komentar Anda. Itu banyak upaya (menarik) yang harus dilalui untuk mengemas beberapa kode menjadi komentar di mana Anda tidak dapat memformatnya dengan benar. Saya masih belum tahu persis apa fungsinya atau, yang lebih penting, mengapa itu mendukung pernyataan Anda (benar).
Joe
110

TL; DR: Lakukan ini sebagai gantinya

Jauh lebih mudah dan lebih mudah dibaca untuk menggunakan fungsi daripada alias untuk meletakkan argumen di tengah-tengah perintah.

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

Jika Anda terus membaca, Anda akan mempelajari hal-hal yang tidak perlu Anda ketahui tentang pemrosesan argumen shell. Pengetahuan itu berbahaya. Dapatkan saja hasil yang Anda inginkan, sebelum sisi gelap selamanya mengendalikan nasib Anda.

Klarifikasi

bashalias melakukan menerima argumen, tetapi hanya pada akhir :

$ alias speak=echo
$ speak hello world
hello world

Menempatkan argumen ke tengah - tengah komando via aliasmemang mungkin tetapi itu menjadi jelek.

Jangan coba ini di rumah, anak-anak!

Jika Anda suka menghindari batasan dan melakukan apa yang orang lain katakan tidak mungkin, inilah resepnya. Hanya saja, jangan salahkan saya jika rambut Anda menjadi kusut dan wajah Anda berakhir dengan jelaga-gaya ilmuwan gila.

Solusinya adalah meneruskan argumen yang aliashanya menerima di akhir ke pembungkus yang akan memasukkannya di tengah dan kemudian jalankan perintah Anda.

Solusi 1

Jika Anda benar-benar menentang penggunaan fungsi, Anda dapat menggunakan:

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

Anda dapat mengganti $@dengan $1jika Anda hanya menginginkan argumen pertama.

Penjelasan 1

Ini menciptakan fungsi sementara f, yang meneruskan argumen (catatan yang fdisebut di bagian paling akhir). The unset -fmenghilangkan definisi fungsi sebagai alias dijalankan sehingga tidak berkeliaran setelah itu.

Solusi 2

Anda juga dapat menggunakan subkulit:

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

Penjelasan 2

Alias ​​membangun perintah seperti:

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

Komentar:

  • Pengganti _diperlukan, tetapi bisa berupa apa saja. Ini akan diatur ke sh's $0, dan diperlukan sehingga pertama dari argumen yang diberikan pengguna tidak bisa dikonsumsi. Demonstrasi:

    sh -c 'echo Consumed: "$0" Printing: "$@"' alcohol drunken babble
    Consumed: alcohol Printing: drunken babble
  • Kutipan tunggal di dalam tanda kutip tunggal diperlukan. Berikut ini contohnya yang tidak bekerja dengan tanda kutip ganda:

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

    Di sini nilai-nilai shell interaktif $0dan $@diganti menjadi dua kali dikutip sebelum diteruskan sh. Inilah buktinya:

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

    Kutipan tunggal memastikan bahwa variabel-variabel ini tidak ditafsirkan oleh shell interaktif, dan diteruskan secara harfiah sh -c.

    Anda dapat menggunakan tanda kutip ganda dan \$@, tetapi praktik terbaik adalah mengutip argumen Anda (karena mungkin mengandung spasi), dan \"\$@\"terlihat lebih jelek, tetapi dapat membantu Anda memenangkan kontes kebingungan di mana rambut yang kusut adalah prasyarat untuk masuk.

Tom Hale
sumber
2
untuk solusi 1, pastikan Anda menggunakan tanda kutip tunggal, dan hindari \ "di sekitar $ @. Teknik yang sangat berguna jika Anda membutuhkannya. ty.
sgtz
Solusi 1 bekerja untuk saya bungkus rdesktop-vrdp dengan argumen untuk setiap server yang saya inginkan.
Hsehdar
Menerima argumen di bagian akhir adalah apa yang saya butuhkan untuk mengganti "git checkout {branchname}" dengan "gc {branchname}" sederhana. Dalam .bash_profile saya hanya perlu menambahkanalias gc='git checkout'
AbstractVoid
@sgtz mengapa Anda ingin menghapus tanda kutip $@? Mereka diperlukan jika Anda memiliki, misalnya, file dengan spasi di dalamnya.
Tom Hale
@ TomHale Ini agak linguistik, tetapi solusi 1 tidak benar-benar berguna jika seseorang benar-benar menentang penggunaan fungsi (apa pun alasannya) karena Anda langsung mengakui bahwa Anda hanya menggeser definisi fungsi ke waktu eksekusi alias. kedua, "alias bash menerima argumen, tetapi hanya pada akhirnya" lebih bersifat semantik: alias per definisi adalah pergantian kata oleh string. mereka tidak perlu menerima argumen, perintah yang dieksekusi melalui substitusi bisa. alias adalah pengganti karakter, tidak lebih, tidak kurang. tidak?
BUFU
39

Solusi alternatif adalah dengan menggunakan marker , alat yang saya buat baru-baru ini yang memungkinkan Anda untuk "mem-bookmark" templat perintah dan dengan mudah menempatkan kursor pada penampung perintah:

penanda baris perintah

Saya menemukan bahwa sebagian besar waktu, saya menggunakan fungsi shell jadi saya tidak perlu menulis perintah yang sering digunakan lagi dan lagi di baris perintah. Masalah menggunakan fungsi untuk use case ini, adalah menambahkan istilah baru ke kosakata perintah saya dan harus mengingat parameter fungsi apa yang merujuk pada perintah-nyata. Tujuan penanda adalah untuk menghilangkan beban mental itu.

Amine Hajyoussef
sumber
14

Yang harus Anda lakukan adalah membuat fungsi di dalam alias:

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

Anda harus menempatkan tanda kutip ganda sekitar "$ 1" karena tanda kutip tunggal tidak akan berfungsi.

Ken Tran
sumber
5
Itu pintar, tapi selain fakta bahwa pertanyaan itu menentukan untuk membuat alias, apakah ada alasan untuk tidak hanya membuat fungsi dengan nama yang sama dengan alias pada awalnya?
xaxxon
1
@xaxxon Tidak juga, tapi ini cara termudah yang saya tahu untuk menggunakan alias, bukan fungsi.
Ken Tran
1
Ini tidak bekerja. Di Ubuntu 18, saya mendapatkan error bash: syntax error near unexpected token '{mkdir'.
Shital Shah
melewatkan sebuah trailing ;di dalam fungsi yang _mkcdkemungkinan besar merupakan kesalahan dari situ.
Jetchisel
Tinggalkan ruang sebelum dan sesudah {dan}
hesham_EE
10

Berikut adalah tiga contoh fungsi yang saya miliki di saya ~/.bashrc, yang pada dasarnya alias yang menerima parameter:

#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
}

Referensi:

Aliteralmind
sumber
Hah? Itu fungsi, bukan alias. Dan salah satu referensi Anda adalah pertanyaan ini.
tripleee
2
Tidak, ini berfungsi persis seperti fungsi. Seperti beberapa jawaban di sini yang dijelaskan, Anda tidak dapat membuat alias yang mengambil parameter. Apa yang dapat Anda lakukan adalah menulis fungsi, yang merupakan apa yang telah Anda lakukan.
tripleee
1
@tripleee Dari sudut pandang pemula saya yang bash, sebelum membaca komentar Anda, saya pikir itu adalah alias (cara alternatif untuk membuatnya). Fungsinya persis seperti satu, sejauh yang saya tahu. Ini pada dasarnya adalah alias yang menerima parameter, bahkan jika saya tidak aktif pada terminologi. Saya tidak melihat masalah. Saya telah mengklarifikasi tautan ke jawaban lain dalam masalah ini. Ini membantu saya membuat ini.
aliteralmind
1
Mungkin ini tidak secara khusus menjawab pertanyaan "alias bash yang menerima parameter", karena saya mengerti sekarang bahwa itu tidak mungkin, tetapi tentu saja secara efektif menjawabnya. Apa yang kulewatkan di sini?
aliteralmind
2
Beberapa contoh sangat bagus di sini, dan kode yang dikomentari dengan baik. Sangat membantu bagi orang-orang yang datang ke halaman ini.
chim
9

Bash alias benar-benar menerima parameter. Saya baru saja menambahkan alias untuk membuat aplikasi reaksi baru yang menerima nama aplikasi sebagai parameter. Inilah proses saya:

Buka bash_profile untuk mengedit di nano

nano /.bash_profile

Tambahkan alias Anda, satu per baris:

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

catatan: "$ @" menerima parameter yang diteruskan seperti "creact my-new-app"

Simpan dan keluar dari editor nano

ctrl + o untuk menulis (tekan enter); ctrl + x untuk keluar

Katakan terminal untuk menggunakan alias baru di .bash_profile

source /.bash_profile

Itu dia! Anda sekarang dapat menggunakan alias baru Anda

Billeh
sumber
6

NB: Jika idenya tidak jelas, itu ide yang buruk untuk menggunakan alias untuk apa pun kecuali alias, yang pertama adalah 'fungsi dalam alias' dan yang kedua adalah 'sulit dibaca redirect / sumber'. Juga, ada kekurangan (yang saya pikir akan menjadi jelas, tetapi kalau-kalau Anda bingung: Saya tidak bermaksud mereka benar-benar digunakan ... di mana saja!)

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

Saya sudah menjawab ini sebelumnya, dan selalu seperti ini di masa lalu:

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

yang bagus dan bagus, kecuali Anda menghindari penggunaan semua fungsi secara bersamaan. dalam hal ini Anda dapat memanfaatkan kemampuan luas bash untuk mengarahkan ulang teks:

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

Keduanya memiliki panjang yang sama memberi atau mengambil beberapa karakter.

The nyata kicker adalah perbedaan waktu, bagian atas menjadi 'metode fungsi dan bagian bawah menjadi metode 'redirect-sumber'. Untuk membuktikan teori ini, waktunya berbicara untuk dirinya sendiri:

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

Ini adalah bagian bawah dari sekitar 200 hasil, yang dilakukan secara berkala. Tampaknya pembuatan / penghancuran fungsi membutuhkan lebih banyak waktu daripada pengalihan. Semoga ini akan membantu pengunjung masa depan untuk pertanyaan ini (tidak ingin menyimpannya untuk saya sendiri).

osirisgothra
sumber
2
Memiliki alias yang mendefinisikan fungsi, kemudian menjalankan fungsi itu konyol. Cukup tulis fungsi. Untuk hampir setiap tujuan, alias digantikan oleh fungsi shell.
geirha
jika Anda tidak membaca semuanya, yang mungkin Anda coba, saya menggambarkan mengapa menggunakan metode fungsi tidak sebagus di tempat pertama, dan lebih jauh lagi, itu tidak konyol sama sekali. Hentikan memposting dan downvoting hanya karena Anda tidak suka secara pribadi ... atau setidaknya memberikan penjelasan yang valid. Memanggil nama adalah tanda pertama pikiran dekat ...
osirisgothra
1
Yang kedua (bilah alias) memiliki beberapa efek samping. Pertama, perintah tidak dapat menggunakan stdin. Kedua, jika tidak ada argumen yang diberikan setelah alias, argumen apa pun yang kebetulan shell telah diteruskan sebagai gantinya. Menggunakan fungsi menghindari semua efek samping ini. (Penggunaan kucing juga tidak berguna).
geirha
2
hei saya tidak pernah mengatakan bahwa itu ide yang baik untuk melakukan semua ini, saya hanya mengatakan ada juga cara lain untuk melakukannya - ide utama di sini adalah bahwa Anda tidak boleh menggunakan fungsi dalam alias karena mereka lebih lambat bahkan daripada rumit redirect, saya pikir itu sudah jelas tapi saya kira saya harus mengejanya untuk semua orang (yang saya juga dimarahi karena posting terlalu membengkak jika saya melakukan itu di tempat pertama)
osirisgothra
1
Karena timing bar semuanya 0, saya menduga bahwa shell tidak menentukan waktu dengan benar. Perhatikan bahwa pesan waktu dicetak sebelum perintah dijalankan? Ergo, itu kali tidak ada dan kemudian melakukan bar, jadi Anda tidak mengukur bar sama sekali. Lakukan sesuatu yang lebih kompleks, atau loop besar di bar sehingga Anda dapat membuatnya lebih jelas bahwa Anda waktu ada
Evan Langlois
6

Jika Anda mencari cara umum untuk menerapkan semua params ke suatu fungsi, bukan hanya satu atau dua atau beberapa jumlah hardcode lainnya, Anda dapat melakukannya dengan cara ini:

#!/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;

Jadi pada contoh di atas, saya meneruskan semua parameter dari saat saya menjalankan runjaralias.

Sebagai contoh, jika saya melakukannya runjar hi thereakan benar-benar berjalan java -jar myjar.jar hi there. Jika saya melakukannya runjar one two threeakan berjalan java -jar myjar.jar one two three.

Saya suka $@solusi berbasis ini karena ia bekerja dengan sejumlah params.

Mikha
sumber
4
mengapa tidak sekadar memberi nama fungsi runjaralih-alih menjadikannya sebagai alias ke fungsi? Tampaknya tidak perlu rumit!
Evan Langlois
Fungsi @EvanLanglois secara otomatis alias-ed (atau memiliki sifat hal diteruskan alias) dalam file bash? jika ya, maka saya tidak tahu
Micah
Tidak mengerti maksud Anda. Alias ​​adalah nama lain, baik itu orang atau fungsi. Jadi, Anda membuat fungsi, lalu Anda membuat nama kedua untuk fungsi tersebut. Tidak ada yang istimewa tentang alias, hanya nama kedua dan tidak diperlukan. Apa yang Anda ketikkan pada baris perintah dapat berupa fungsi internal atau eksternal, jadi "function" membuat perintah baru, bukan alias.
Evan Langlois
4
Ini tidak ada gunanya. Itu sama dengan alias runjar='java -jar myjar.jar'. Alias ​​menerima argumen, tetapi hanya di akhir.
Tom Hale
6

Dengan hormat kepada semua yang mengatakan Anda tidak dapat memasukkan parameter di tengah alias saya baru saja mengujinya dan ternyata itu berhasil.

alias mycommand = "python3" $ 1 "script.py --folderoutput HASIL /"

ketika saya menjalankan perintah foobar saya, perintah itu bekerja persis seperti jika saya mengetik perintah itu dengan tangan.

Nathaniel
sumber
Tentu saja, alias bisa mendapatkan parameter, saya sudah lama menggunakan ini misalnya: alias commit = "git commit -m $ 1"
agapitocandemor
Tidak bekerja untuk saya: alias myalias="echo 1 "$1" 3"; myalias 2beri saya:1 3 2
dirdi
4

Ada alasan teknis yang sah untuk menginginkan solusi umum untuk masalah bash alias tidak memiliki mekanisme untuk mengambil reposisi argumen sewenang-wenang. Salah satu alasannya adalah jika perintah yang ingin Anda jalankan akan terpengaruh oleh perubahan lingkungan yang dihasilkan dari menjalankan fungsi. Dalam semua kasus lain , fungsi harus digunakan.

Apa yang baru-baru ini memaksa saya untuk mencoba solusi untuk ini adalah bahwa saya ingin membuat beberapa perintah singkat untuk mencetak definisi variabel dan fungsi. Jadi saya menulis beberapa fungsi untuk tujuan itu. Namun, ada variabel tertentu yang (atau mungkin) diubah oleh pemanggilan fungsi itu sendiri. Diantaranya adalah:

FUNCNAME BASH_SOURCE BASH_LINENO BASH_ARGC BASH_ARGV

Perintah dasar yang saya gunakan (dalam suatu fungsi) untuk mencetak variabel defns. dalam bentuk output oleh perintah set adalah:

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

Misalnya:

> V=voodoo
sv V
V=voodoo

Masalah: Ini tidak akan mencetak definisi variabel yang disebutkan di atas karena mereka berada dalam konteks saat ini , misalnya, jika dalam prompt shell interaktif (atau tidak dalam panggilan fungsi apa pun), FUNCNAME tidak didefinisikan. Tetapi fungsi saya memberi tahu saya informasi yang salah:

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

Salah satu solusi yang saya temukan telah disebutkan oleh orang lain di posting lain tentang topik ini. Untuk perintah khusus ini untuk mencetak variabel, dan yang hanya membutuhkan satu argumen, saya melakukan ini:

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

Yang memberikan output yang benar (tidak ada), dan status hasil (salah):

> asv FUNCNAME
> echo $?
1

Namun, saya masih merasa harus menemukan solusi yang berfungsi untuk sejumlah argumen yang berubah-ubah.

Solusi Umum Untuk Melewati Argumen Sewenang-wenang Pada Perintah Bash Alias:

# (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".

Misalnya:

> . 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

Satu hal yang menyenangkan tentang solusi ini adalah bahwa semua trik khusus yang digunakan untuk menangani parameter posisi (argumen) untuk perintah akan bekerja ketika menyusun perintah yang terperangkap. Satu-satunya perbedaan adalah sintaks array harus digunakan.

Misalnya,

Jika Anda ingin "$ @", gunakan "$ {CMD_ARGV [@]}".

Jika Anda ingin "$ #", gunakan "$ {# CMD_ARGV [@]}".

Dll

crobc1
sumber
3

Setelah saya melakukan beberapa proyek yang menyenangkan dan saya masih menggunakannya. Ini menunjukkan beberapa animasi sementara saya menyalin file melalui cpperintah karena cptidak menunjukkan apa-apa dan itu agak frustasi. Jadi saya membuat alias ini

alias cp="~/SCR/spiner cp"

Dan ini adalah skrip spiner

#!/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

Terlihat seperti ini

masukkan deskripsi gambar di sini

Animasi bersepeda)

masukkan deskripsi gambar di sini

Ivan
sumber
2

Untuk mengambil parameter, Anda harus menggunakan fungsi!

Namun $ @ diinterpretasikan ketika membuat alias alih-alih selama eksekusi alias dan melarikan diri $ juga tidak berfungsi. Bagaimana saya mengatasi masalah ini?

Anda perlu menggunakan fungsi shell alih-alih alias untuk menyingkirkan masalah ini. Anda dapat mendefinisikan foo sebagai berikut:

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

ATAU

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

Terakhir, panggil foo Anda () menggunakan sintaks berikut:

foo arg1 arg2 argN

Pastikan Anda menambahkan foo () ke ~/.bash_profileatau ~/.zshrcfile Anda.

Dalam kasus Anda, ini akan berhasil

function trash() { mv $@ ~/.Trash; }
Ahmad Awais
sumber
Saya tidak mengerti ide Anda. Saya pikir itu tidak penting ketika argumen ditafsirkan. Alias ​​menerima parameter sebanyak yang Anda inginkan di akhir.
Timo
Tetapi lebih baik melakukannya dengan fungsi. Alias ​​tidak dimaksudkan untuk itu.
Ahmad Awais
1

Fungsinya memang hampir selalu merupakan jawaban karena sudah banyak dikontribusikan dan dikonfirmasi oleh kutipan dari halaman manual ini: "Untuk hampir setiap tujuan, alias digantikan oleh fungsi shell."

Untuk kelengkapan dan karena ini dapat berguna (sintaksis sedikit lebih ringan) dapat dicatat bahwa ketika parameter mengikuti alias, mereka masih dapat digunakan (meskipun ini tidak akan memenuhi persyaratan OP). Ini mungkin yang paling mudah ditunjukkan dengan contoh:

alias ssh_disc='ssh -O stop'

memungkinkan saya untuk mengetik seperti ssh_disc myhost, yang akan diperluas seperti yang diharapkan:ssh -O stop myhost

Ini bisa berguna untuk perintah yang membutuhkan argumen kompleks (ingatan saya tidak seperti apa lagi ...)

sxc731
sumber
1

Baik fungsi dan alias dapat menggunakan parameter seperti yang telah ditunjukkan di sini. Selain itu, saya ingin menunjukkan beberapa aspek lain:

1. fungsi berjalan dalam ruang lingkupnya sendiri, alias ruang lingkup saham

Mungkin berguna untuk mengetahui perbedaan ini jika Anda perlu menyembunyikan atau mengekspos sesuatu. Ini juga menunjukkan bahwa fungsi adalah pilihan yang lebih baik untuk enkapsulasi.

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 

Keluaran:

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. skrip wrapper adalah pilihan yang lebih baik

Telah terjadi pada saya beberapa kali bahwa alias atau fungsi tidak dapat ditemukan ketika masuk melaluissh atau melibatkan beralih nama pengguna atau lingkungan multi-pengguna. Ada tips dan trik dengan sumber file dot, atau yang menarik ini dengan alias: alias sd='sudo 'memungkinkan alias berikutnya ini alias install='sd apt-get install'berfungsi seperti yang diharapkan (perhatikan ruang tambahan di sd='sudo '). Namun, skrip wrapper berfungsi lebih baik daripada fungsi atau alias dalam kasus seperti ini. Keuntungan utama dengan skrip wrapper adalah skrip ini dapat dilihat / dieksekusi untuk di bawah jalur yang dimaksudkan (yaitu / usr / loca / bin /) di mana sebagai fungsi / alias perlu bersumber sebelum dapat digunakan. Misalnya, Anda meletakkan fungsi dalam ~ / .bash_profile atau ~ / .bashrc untuk bash, tetapi kemudian beralih ke shell lain (yaituzsh) maka fungsinya tidak terlihat lagi. Jadi, ketika Anda ragu, skrip wrapper selalu merupakan solusi yang paling andal dan portabel.

biocyberman
sumber
1
Menurut Anda mengapa versi fungsi tidak berfungsi?
rangkap tiga
@ tripleee. Saya telah mengedit posting untuk membuatnya lebih mudah dibaca. Di bawah judul "1. alias berfungsi, fungsi ..." Saya menggambarkan mengapa versi fungsi tidak berfungsi. Dan mungkin untuk menjawab pertanyaan secara langsung, fungsi memperkenalkan ruang lingkup baru di mana alias tidak.
biocyberman
Anda mengatakan itu tidak berhasil tetapi saya tidak percaya Anda. sourcedalam suatu fungsi berfungsi dengan baik.
tripleee
1
f () { source /tmp/nst; }tidak persis apa yang saya harapkan. Mungkin Anda PATHsalah sehingga menjalankan yang salah activateatau sesuatu; tetapi lari sourcedari suatu fungsi berfungsi dengan baik.
tripleee
1
BTW, ulang: menggunakan functionkata kunci dalam definisi Anda, lihat wiki.bash-hackers.org/scripting/obsolete - function funcname {adalah sintaks ksh kuno dukungan bash untuk kompatibilitas mundur dengan kulit pra-POSIX, sedangkan funcname() {sintaksis resmi POSIX-standar. function funcname() {adalah mismash dari keduanya yang tidak kompatibel dengan ksh kuno atau kompatibel dengan POSIX sh, dan yang dengan demikian sebaiknya dihindari.
Charles Duffy
1

Inilah contohnya:

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

Sangat penting:

  1. Ada ruang setelah {dan sebelumnya }.
  2. Ada ;setelah setiap perintah secara berurutan. Jika Anda lupa ini setelah perintah terakhir, Anda akan melihat >prompt sebagai gantinya!
  3. Argumen terlampir dalam tanda kutip sebagai "$1"
Shital Shah
sumber
2
Tidak perlu membuat alias ke suatu fungsi, cukup gunakan fungsinya secara langsung.
user3439894
1

Seperti yang telah ditunjukkan oleh orang lain, menggunakan fungsi harus dianggap praktik terbaik.

Namun, berikut adalah pendekatan lain, meningkatkan xargs:

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

Perhatikan bahwa ini memiliki efek samping sehubungan dengan pengalihan aliran.

dirdi
sumber
0

Anda tidak perlu melakukan apa-apa, alias melakukan ini secara otomatis.

Sebagai contoh, jika saya ingin membuat git pull asal parameter, saya bisa membuat alias sebagai berikut:

alias gpull = 'git pull origin '

dan ketika benar-benar memanggilnya, Anda dapat mengirimkan 'master' (nama cabang) sebagai parameter, seperti ini:

gpull master
//or any other branch
gpull mybranch
KayV
sumber
Ini tidak menjawab pertanyaan, karena argumen tidak dapat ditempatkan secara bebas, tetapi hanya di bagian akhir.
dirdi