Cara memperpanjang alias bash

11

Bagaimana cara membuat alias yang benar-benar memperluas alias lain dengan nama yang sama di Bash?

Mengapa:

Saya dulu telah GREP_OPTIONSmenetapkan .bashrcsesuatu seperti ini:

GREP_OPTIONS="-I --exclude=\*~"

Saya juga punya skrip (katakanlah, setup-java.sh) yang akan saya panggil sebelum mengerjakan beberapa proyek Java. Itu akan berisi baris:

GREP_OPTIONS="$GREP_OPTIONS --exclude-dir=classes"

Jika saya juga menggunakan Sass, maka saya akan menelepon setup-sass.shyang berisi baris:

GREP_OPTIONS="$GREP_OPTIONS --exclude-dir=\*/.sass-cache"

Tetapi GREP_OPTIONSsudah usang dan tampaknya solusi standar adalah membuat alias atau beberapa skrip ...

brandizzi
sumber
Bagaimana dengan fungsi bash?
Jakuje
2
Saya cukup setuju - menggunakan fungsi adalah opsi yang jauh lebih baik daripada alias.
Charles Duffy

Jawaban:

13

Bash menyimpan nilai alias dalam array yang disebut BASH_ALIASES :

$ alias foo=bar
$ echo ${BASH_ALIASES[foo]}
bar

Dengan ekspansi parameter kita bisa mendapatkan alias set terakhir (jika ada) atau nilai default:

alias grep="${BASH_ALIASES[grep]:-grep} -I --exclude=\*~"

Sekarang lakukan saja setup-java.sh:

alias grep="${BASH_ALIASES[grep]:-grep} -I --exclude=\*~  --exclude-dir=classes"

... dan akhirnya setup-sass.sh:

alias grep="${BASH_ALIASES[grep]:-grep} -I --exclude=\*~ --exclude-dir=\*/.sass-cache"

Jika tiga baris dipanggil, kita mendapatkan apa yang kita inginkan:

$ echo ${BASH_ALIASES[grep]:-grep}
grep -I --exclude=\*~ -I --exclude=\*~ --exclude-dir=classes -I --exclude=\*~ --exclude-dir=\*/.sass-cache
brandizzi
sumber
13

aliases rantai jika Anda mengakhirinya dengan spasi.

alias print='printf %s\\n ' hey='"hello, fine fellow" '
print hey

hello, fine fellow

Anda dapat menulis seluruh skrip dengan cara itu, jika Anda cukup gila. Lagi pula, jika Anda ingin memperpanjang alias, maka pastikan alias yang Anda ingin perpanjang berakhir di spasi, dan tempel yang lain di.

alias grep='printf "%s " -I --exclude=\*~ '    \
      exdir=' --exclude-dir=classes '          \
      exsass='--exclude-dir=\*/.sass-cache '
grep exdir exsass exdir exsass

-I --exclude=*~ --exclude-dir=classes --exclude-dir=*/.sass-cache --exclude-dir=classes --exclude-dir=*/.sass-cache
mikeserv
sumber
7
Ini indah sekali.
user1717828
Wow, ini luar biasa. Tidak tahu ini (dan mungkin tidak akan banyak menggunakannya, karena saya pikir itu bertentangan dengan Aturan Kejelasan ) tetapi itu bagus untuk diketahui! Pertanyaan, meskipun: Mengapa ruang pada awal exdir? (Apakah itu hanya untuk penyelarasan karena alasan estetika?)
Wildcard
2
@Wildcard: fnmatch(){ alias fnmatch='case $1 in '; while "${1:+:}" 2>&-; do eval 'fnmatch pattern list ;; esac'; shift; done; unalias fnmatch; }; alias pattern='${1:+*}) ' list=': do stuff '; fnmatch "$@". Melakukannya dengan aliasesmemungkinkan Anda untuk menggunakan ekspansi pola lebih langsung dan lebih aman. Anda memang membutuhkan konteks kedua evalketika dipanggil dari dalam suatu fungsi, tetapi itu pada dasarnya tidak aman selama patterndan listnamanya dikontrol oleh Anda. Mereka hanya dapat mematahkan dalam kebanyakan kasus bahkan ketika mereka tidak kecuali beberapa penyerang dengan sengaja mengakhiri Anda case.
mikeserv
1
Saya menggunakan pola ini di .bashrc: saya alias sudo='sudo ', ini memungkinkan saya memanggil semua perintah alias saya setelah a sudo. Tanpa ruang itu tidak akan berhasil
aroneone
1
@Wildcard - Saya tidak menganjurkan penggunaan seperti itu, tetapi memang benar Anda bisa, dan itu juga benar Anda harus setidaknya sedikit gila untuk mencoba.
mikeserv
2

Fungsi adalah opsi yang lebih baik daripada alias yang bisa diperpanjang di sini.

grep_options=( )
grep() {
  exec /usr/bin/grep "${grep_options[@]}" ${GREP_OPTIONS} "$@"
}

Dengan begitu, Anda memiliki dua opsi untuk menambahkan opsi ke lingkungan:

  • Ubah grep_optionsarray; ini dengan benar mendukung opsi dengan spasi, karakter gumpal literal, dan kasing sudut lainnya:

    grep_options+=( --exclude-dir=classes --exclude-dir='*/.sass-cache' )
  • Gunakan GREP_OPTIONSvariabel skalar tradisional , meskipun ada jebakannya (lihat BashFAQ # 50 untuk memahami beberapa di antaranya):

    GREP_OPTIONS+=' --exclude-dir=classes '

Yang mengatakan, jika Anda ingin opsi Anda dicerminkan oleh grepinstance yang dipanggil di luar shell, tidak ada alias atau fungsi yang akan dilakukan. Sebagai gantinya, Anda ingin skrip pembungkus ditempatkan lebih awal di PATH Anda daripada grepperintah yang sebenarnya . Misalnya:

# in ~/.bash_profile
[[ -e ~/bin ]] && PATH=$HOME/bin:$PATH

... dan di ~/bin/grep:

#!/bin/bash

# load overrides to grep_options on GREP_OPTIONS from local dotfiles
source ~/.bash_profile
source ~/.bashrc

# ...and use them:
exec /usr/bin/grep "${grep_options[@]}" ${GREP_OPTIONS} "$@"
Charles Duffy
sumber