Bagaimana menjalankan alias dalam skrip shell?

101

Saya memiliki file yang dapat dieksekusi mpiexec, yang path lengkapnya adalah ~/petsc-3.2-p6/petsc-arch/bin/mpiexec. Karena saya ingin menjalankan perintah ini di direktori yang berbeda (tanpa harus mengetik ulang seluruh path), saya menyiapkan alias di .bashrcfile rumah saya :

alias petsc="~/petsc-3.2-p6/petsc-arch/bin/mpiexec"  

yang memungkinkan saya untuk mengeksekusi mpiexecfile ini di command prompt dengan mudah dengan mengetik:

petsc myexecutable

Saya mencoba menulis file skrip shell, bernama script, menggunakan alias baru saya petscsebagai perintah. Setelah memberikan skrip shell saya izin yang sesuai (menggunakan chmod), saya mencoba menjalankan skrip. Namun, itu memberi saya kesalahan berikut:

./script: line 1: petsc: command not found

Saya tahu bahwa saya hanya bisa menulis path lengkap ke mpiexecfile, tetapi sulit untuk menulis path lengkap setiap kali saya ingin menulis skrip baru. Apakah ada cara agar saya dapat menggunakan alias saya petscdi dalam file skrip? Apakah ada cara saya dapat mengedit .bashrcatau .bash_profilemembuat ini terjadi?

Paul
sumber
Bagaimana dengan menambahkan alias ke .bash_aliases? Juga bagaimana dengan aliasing jalur absolut dan bukan jalur relatif sepertialias petsc='/home/user/petsc-3.2-p6/petsc-arch/bin/mpiexec'
Nitin Venkatesh
@ nitstorm: Tidak ada solusi yang berfungsi ... Saya masih mendapatkan kesalahan yang sama seperti sebelumnya
Paul
Terkait: unix.stackexchange.com/questions/1496/…
AlikElzin-kilaka

Jawaban:

74
  1. Dalam skrip shell Anda gunakan path lengkap daripada alias.

  2. Dalam skrip shell Anda, tetapkan sintaks variabel yang berbeda

    petsc='/home/your_user/petsc-3.2-p6/petsc-arch/bin/mpiexec'
    
    $petsc myexecutable
    
  3. Gunakan fungsi dalam skrip Anda. Mungkin lebih baik jika petscrumit

    function petsc () {
        command 1
        command 2
    }
    
    petsc myexecutable
    
  4. Sumber alias Anda

    shopt -s expand_aliases
    source /home/your_user/.bashrc
    

Anda mungkin tidak ingin sumber Anda .bashrc, jadi, IMO, salah satu dari 3 pertama akan lebih baik.

Harimau kumbang
sumber
16
Poin 4 tidak berfungsi, kecuali jika Anda menggunakan shopt -s expand_aliasesskrip yang sama.
enzotib
Saran Anda 2) berfungsi, tetapi saya ingin dapat menggunakan perintah yang sama di banyak skrip shell tanpa harus menulis baris pertama petsc = "...". Apakah ada cara untuk melakukan ini?
Paul
1
@enzotib - terima kasih, saya menambahkan itu ke jawaban saya.
Panther
1
Di poin 2 Anda tidak menetapkan alias tetapi variabel.
pabouk
1
Tidak diminta oleh OP tetapi relevan dengan judul pertanyaan: Poin 2 tidak akan berfungsi dengan perintah yang mengandung |. Di sini, gunakan shopt -s expand_aliases& alias lokal, mis. alias myalias='echo abc|rev'- membutuhkan jeda baris sebelum digunakan (lihat ALIAS di man bash). Butir 4: File bersumber dapat mencegah eksekusi non-interaktif, yaitu dalam skrip. Cari lebih awal exitatau return, misalnya [ -z "$PS1" ] && return(memeriksa apakah prompt utama tidak disetel yang menunjukkan shell non-interaktif) atau mungkin ada check iin $-( $-berisi opsi shell, iberarti interaktif). Lihat man bashvariabel-variabel itu.
berlaku
62

Alias ​​tidak digunakan lagi karena fungsi shell. Dari bashhalaman manual:

For almost every purpose, aliases are superseded by shell functions.

Untuk membuat fungsi, dan ekspor ke subkulit, masukkan yang berikut ini di ~/.bashrc:

petsc() {
    ~/petsc-3.2-p6/petsc-arch/bin/mpiexec "$@"
}
export -f petsc

Kemudian Anda dapat dengan bebas memanggil perintah dari skrip Anda.

enzotib
sumber
Itu hampir berfungsi ... satu-satunya masalah adalah bahwa saya harus dapat memberikan flag yang berbeda ke "mpiexec" yang dapat dieksekusi ... Misalnya, saya harus dapat menjalankan sesuatu seperti "petsc -n 40 myexecutable" dengan alias "petsc"
Paul
4
@ Paul: Saya menambahkan "$@"hanya untuk menangani argumen.
enzotib
12

Fungsi dan alias Shell terbatas pada shell dan tidak berfungsi di skrip shell yang dieksekusi. Alternatif untuk kasus Anda:

  • (jika Anda tidak repot-repot menggunakannya, mpiexecbukan petsc) Tambahkan $HOME/petsc-3.2-p6/petsc-arch/binke PATHvariabel Anda . Ini dapat dilakukan dengan mengedit ~/.profiledan menambahkan:

    PATH="$HOME/petsc-3.2-p6/petsc-arch/bin:$PATH"

    Login ulang untuk menerapkan perubahan ini

  • Buat direktori ~/bindan

    • buat skrip wrapper dengan nama yang petscmengandung:

      #!/bin/sh
      exec ~/petsc-3.2-p6/petsc-arch/bin/mpiexec "$@"
      
    • jika program memungkinkan, Anda dapat melewati shellscript dan membuat symlink menggunakan perintah:

      ln -s ~/petsc-3.2-p6/petsc-arch/bin/mpiexec ~/bin/petsc
Lekensteyn
sumber
9

Di bash 4 Anda dapat menggunakan variabel khusus: $BASH_ALIASES.

Sebagai contoh:

$ alias foo="echo test"
$ echo ${BASH_ALIASES[foo]}
echo test
$ echo `${BASH_ALIASES[foo]}` bar
test bar

Atau tentukan sebagai variabel kemudian gunakan substitusi perintah atau eval.

Jadi misalnya, alih-alih mendefinisikan alias seperti:

alias foo="echo test"

mendefinisikannya sebagai:

foo="echo test"

sebagai gantinya. Kemudian jalankan dengan:

find . -type f -exec sh -c "eval $foo" \;

atau:

find . -type f -exec sh -c "echo `$foo`" \;
kenorb
sumber
Walaupun alias tidak digunakan lagi karena fungsi shell, jawaban ini adalah satu-satunya yang harus diterima. Bahkan Debian 8 yang lama memiliki versi bash, jadi ${BASH_ALIASES[alias]}ini pilihan yang bagus. Kalau tidak, saya harus mengedit banyak baris .bash_aliases saya untuk menerapkan hal-hal lain. Terima kasih.
erm3nda
8

Anda bisa memaksa bash untuk mengeksekusi skrip Anda sebagai shell interaktif dengan flag -i. Ini akan memberi tahu file .bashrc Anda untuk menentukan alias dan fungsi lainnya.

Contoh:

~ $ grep ll .bashrc
alias ll='ls -lah'
~ $ cat script.sh 
#!/bin/sh

ll
~ $ bash script.sh 
script.sh: line 3: ll: command not found
~ $ bash -i script.sh
..directory contents..

Info lebih lanjut:

$ man bash
Amado Martinez
sumber
2
.bashrcjuga dibaca selama eksekusi perintah SSH non-interaktif (itu sebabnya ia memiliki cek untuk interaktivitas di atas)
muru
6
ALIASES
   ...
   Aliases are not expanded when the shell is not interactive, unless the expand_aliases shell option is set using shopt (see the description of shopt under SHELL BUILTIN COMMANDS
   below).

Jadi jawaban sebenarnya untuk pertanyaan ini, bagi mereka yang ingin menggunakan alias aktual dalam skrip shell alih-alih alternatifnya, adalah:

#!/bin/bash

shopt -s expand_aliases

alias foo=bar

foo whatever

Adapun mengapa saya ingin melakukan ini: Karena keadaan yang tidak biasa, saya perlu menipu Dockerfile untuk berpikir itu adalah skrip shell.

Membuang Akun
sumber
4
  1. Di .bash_aliases:

    petsc {
    ~/petsc-3.2-p6/petsc-arch/bin/mpiexec "$@"
    }
    

    Atau masukkan fungsi .bashrc. Biasanya .bashrchanya pengaturan konfigurasi bashyang disimpan.

  2. Di Terminal: source .bash_aliases

  3. Sebut saja: petsc arg(s)

Keuntungan: Anda tidak perlu export -f petscdi .bash_aliases. Alias ​​sudah usang tetapi menggunakan .bash_aliasesuntuk fungsi tidak masalah.

Timo
sumber
Saya suka solusi ini, saya akan mencobanya nanti
Greenonline
2
  1. Gunakan alias Anda di skrip shell Anda.
  2. Sumber skrip Anda di shell interaktif Anda saat ini, bukannya mengeksekusi

Jadi jika Anda memiliki file yang dipanggil script.shdengan perintah Anda yang termasuk menggunakan alias, cukup ketik:

source script.sh
Gordon Erlebacher
sumber
@ DavidFoerster Metode ini berfungsi dengan baik. Sumber skrip dengan .atau sourcebuiiltin menyebabkan shell saat ini untuk menjalankan semua perintah di dalamnya. Jika ekspansi alias akan terjadi di shell di mana .atau sourcedijalankan, itu terjadi. Namun, penting untuk menyadari bahwa metode ini hanya kadang-kadang berguna, karena sering kali seseorang perlu atau ingin menjalankan skrip di shell sendiri, dengan lingkungannya sendiri. Skrip shell yang ditulis dengan tujuan dieksekusi dengan cara yang biasa tidak seharusnya diambil dari sumbernya - skrip tersebut seringkali tidak berfungsi dengan baik.
Eliah Kagan
@EliahKagan: Terima kasih. Sekarang saya mengerti apa artinya jawaban itu. Saya akan menambahkan penjelasan.
David Foerster
1

(EDIT: fungsi yang dihapus karena saya salah membaca panggilan mpiexec.)

Jika satu-satunya yang Anda butuhkan adalah kurang mengetik, mengapa Anda tidak memasukkan folder ke dalam $ PATH? Atau buat symlink ke mpiexec dari beberapa folder dalam $ PATH? Atau (favorit saya) memasukkan alias dalam skrip yang Anda sumber dalam skrip panggilan?

tidak tahu malu
sumber
1
Alasan mengapa saya tidak dapat memasukkannya ke $ PATH saya adalah karena saya mempunyai file 'mpiexec' lain di direktori lain yang juga sudah ada di $ PATH saya. Jika saya menambahkan path ke 'mpiexec' baru ini, mungkin akan mencoba untuk mengeksekusi keduanya ... bukan?
Paul
1
Tidak bisa mengerti mengapa tidak digunakan saja "$@".
enzotib
2
Paul, itu akan mencoba untuk mengeksekusi yang pertama di PATH, bukan keduanya.
Unhammer
enzotib, ah saya salah membaca cara mpiexec dipanggil, saya pikir itu membutuhkan semua argumen sebagai satu. Akan mengedit jawaban saya :)
unhammer