Mengapa skrip Bash saya tidak mengenali alias?

216

Dalam ~/.bashrcfile saya ada dua definisi:

  1. commandA, yang merupakan alias ke jalur yang lebih panjang
  2. commandB, yang merupakan alias untuk skrip Bash

Saya ingin memproses file yang sama dengan dua perintah ini, jadi saya menulis skrip Bash berikut:


#!/bin/bash

for file in "$@"
    do
    commandA $file
    commandB $file
done

Bahkan setelah keluar dari sesi saya dan masuk kembali, Bash meminta saya dengan command not foundkesalahan untuk kedua perintah ketika saya menjalankan skrip ini.

Apa yang saya lakukan salah?

Zaid
sumber
10
BTW, tidak perlu masuk dan keluar untuk memiliki alias yang dikenali. Anda hanya perlu melakukannya source ~/.bashrc.
tshepang
Untuk kasus saya, saya terhubung dengan agen SSH dari jarak jauh, setelah menambahkan alias ketika saya menutup agen SSH dan terhubung lagi itu mulai bekerja.
dav
Alias ​​adalah cara mempersingkat perintah. (Mereka hanya digunakan dalam shell interaktif dan bukan dalam skrip - ini adalah salah satu dari sedikit perbedaan antara skrip dan shell interaktif.)
Kris Roofe

Jawaban:

117

Pertama-tama, seperti yang dikatakan ddeimeke, alias secara default tidak diperluas di shell yang tidak interaktif.

Kedua, .bashrctidak dibaca oleh cangkang non-interaktif kecuali jika Anda mengatur BASH_ENVvariabel lingkungan.

Tetapi yang paling penting: jangan lakukan itu! Silahkan? Suatu hari Anda akan memindahkan script itu ke suatu tempat di mana alias yang diperlukan tidak diatur dan itu akan rusak lagi.

Alih-alih mengatur dan menggunakan variabel lingkungan sebagai pintasan dalam skrip Anda:

#!/bin/bash

CMDA=/path/to/gizmo
CMDB=/path/to/huzzah.sh

for file in "$@"
do
    $CMDA "$file"
    $CMDB "$file"
done

sumber
5
Solusi itu tidak berfungsi untuk aliaskasus penggunaan biasa . Misalnya alias mv="mv -v --backup=numbered".
Evi1M4chine
@ Evi1M4chine: Ya, benar. Setidaknya setelah saya mengembalikan suntingan yang tidak perlu Gilles. Namun, mungkin lebih baik menggunakan variabel yang berbeda untuk parameter.
1
Ah, perhatikan kurangnya tanda kutip di sekitar $CMDA/ $CMDB... Terlepas dari variabel huruf besar yang dicadangkan untuk bash sendiri di bash, dan itu memang berfungsi, bahwa kurangnya tanda kutip membuat saya benar-benar gelisah ... Terima kasih.
Evi1M4chine
@ Evi1M4chine: Eh, apa? 1. Saya menghapus tanda kutip sendiri di edit terbaru. 2. di mana Anda mendapatkan "dicadangkan untuk bash sendiri" dari? ini akan menjadi yang pertama saya dengar. 3. Jika itu membuat Anda gelisah, bagaimana perasaan Anda tentang menggunakan bash sejak awal? Pokoknya, gunakan variabel terpisah untuk opsi seperti yang saya katakan.
1
@alvas: asumsinya adalah bahwa gizmotidak di jalan atau ada perintah dengan nama yang sama tetapi prioritas yang lebih tinggi. kalau tidak Anda bisa mengatur sederhana CMDAke dataran gizmodi tempat pertama.
161

Jika Anda melihat ke halaman manual bash, Anda menemukan:

Alias ​​tidak diperluas ketika shell tidak interaktif, kecuali jika opsi shell expand_aliases diatur menggunakan shopt (lihat deskripsi shopt di bawah SHELL BUILTIN COMMANDS di bawah).

Jadi letakkan a

shopt -s expand_aliases

dalam skrip Anda.

Pastikan untuk mencari file alias Anda setelah mengatur ini di skrip Anda.

shopt -s expand_aliases
source ~/.bash_aliases
ddeimeke
sumber
7
Saya menempatkannya di skrip saya, tetapi masih tidak berfungsi. Kesalahan yang sama.
Zaid
5
Menambahkan shopt -s expand_aliases source ~/.bash_aliasesberfungsi dengan baik untuk saya. Seringkali ada bentuk deteksi shell interaktif di .bashrc seperti ini: # If not running interactively, don't do anything [ -z "$PS1" ] && return@Zaid, Mungkin Anda ingin memeriksa itu di file yang Anda gunakan.
Frank Schubert
1
luar biasa! menyimpan skrip saya !! :) sangat sulit untuk membaca / mencari / menelusuri info dan halaman manual di terminal yang baru saja saya tinggalkan dan mencari di internet ...
Aquarius Power
2
Anehnya, shopt -s expand_aliasestidak harus pergi sebelum definisi alias tetapi sebelum menggunakan alias. Menambahkan ke @FrankSchubert: Deteksi shell interaktif juga dapat dilakukan dengan menggunakan $-yang berisi opsi untuk shell, khususnya ijika shell bersifat interaktif.
berlaku
2
ini bukan jawaban yang benar ... Sumber alias Anda di dalam skrip Anda bukan jawabannya. Anda ~/.bash_aliasesmungkin bergantung pada hal-hal lain yang sebelumnya dimuat pada shell interaktif ... Hal terdekat yang saya temukan adalah mengubah hashbang Anda menjadi #!/bin/bash -liMasih tidak sempurna. Idealnya Anda harus menggunakan fungsi dan bukan alias.
Stefanos Kalantzis
44

Alias ​​tidak dapat diekspor sehingga tidak tersedia dalam skrip shell yang tidak didefinisikan. Dengan kata lain, jika Anda mendefinisikannya di ~/.bashrcmereka tidak tersedia untuk your_script.sh(kecuali Anda sumber ~/.bashrcdalam skrip, yang saya tidak akan merekomendasikan tetapi ada cara untuk melakukan ini dengan benar).

Namun, fungsi dapat diekspor dan akan tersedia untuk shell skrip yang dijalankan dari lingkungan di mana mereka didefinisikan. Ini bisa dilakukan dengan menempatkan ini di bashrc Anda:

foo ()
{
    gema "Halo Dunia!"
}
ekspor-f foo

Seperti yang dikatakan dalam manual Bash, "Untuk hampir semua tujuan, fungsi shell lebih disukai daripada alias."

Dennis Williamson
sumber
1
Meskipun ini tidak secara teknis menjawab pertanyaan, seperti yang Anda katakan, Anda bisa langsung mengganti alias commandA=...dengan commandA() { ... }itu export commandAdan Anda mendapatkan perilaku yang identik dengan alias. Jadi ini cukup banyak alternatif yang identik dengan alias sejauh yang saya tahu itu sangat bagus dalam skrip bash
Phylliida
Masalahnya di sini adalah ketika Anda membutuhkan alias yang Anda berikan banyak pilihan dikutip. misalnya sebagai contoh, alias b=bashmembuatnya mudah dilakukan b -c "echo test | grep test"yang akan sulit dilakukan dalam fungsi.
Fmstrat
@Fmstrat: b () { bash "$@"; }lalub -c "echo test | grep test"
Dennis Williamson
11
[cmd line] > bash -i [your script's file path]

Ini iuntuk interaktif dan sumber bashprofil Anda untuk Anda.

pengguna65576
sumber
-5

Saya menemukan kadang-kadang skrip bash juga tidak mengenali ekspor. Namun, mengubahnya menjadi

#!/bin/sh

bekerja untukku.

lwpro2
sumber
1
Tidak, itu tidak ...
Hafiz Temuri