Làm thế nào để mở rộng bí danh bash


11

Làm thế nào để tạo một bí danh thực sự mở rộng một bí danh khác cùng tên trong Bash?

Tại sao:

Tôi đã từng GREP_OPTIONSthiết lập .bashrcmột cái gì đó như thế này:

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

Tôi cũng đã có một đoạn script (giả sử chúng ta sẽ nói setup-java.sh) mà tôi sẽ gọi trước khi làm việc với một số dự án Java. Nó sẽ chứa dòng:

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

Nếu tôi cũng sử dụng Sass, thì tôi sẽ gọi setup-sass.shtrong đó có dòng:

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

Nhưng GREP_OPTIONSđã bị phản đối và rõ ràng giải pháp tiêu chuẩn là tạo ra bí danh hoặc một số tập lệnh ...


Còn chức năng bash thì sao?
Jakuje

2
Tôi hoàn toàn đồng ý - sử dụng một chức năng là một lựa chọn tốt hơn nhiều so với bí danh.
Charles Duffy

Câu trả lời:


13

Bash lưu trữ các giá trị của bí danh trong một mảng được gọi là BASH_ALIASES :

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

Với việc mở rộng tham số, chúng ta có thể lấy bí danh được đặt cuối cùng (nếu tồn tại) hoặc giá trị mặc định:

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

Bây giờ chỉ cần làm điều đó trên setup-java.sh:

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

... và cuối cùng là setup-sass.sh:

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

Nếu ba dòng được gọi, chúng ta sẽ có được những gì chúng ta muốn:

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

13

aliases chuỗi nếu bạn kết thúc chúng với không gian.

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

hello, fine fellow

Bạn có thể viết toàn bộ kịch bản theo cách đó, nếu bạn đủ điên rồ. Dù sao, nếu bạn muốn mở rộng bí danh, thì hãy chắc chắn rằng bí danh bạn muốn kéo dài kết thúc trong một khoảng trắng, và giải quyết một bí danh khác.

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

7
Thật là đẹp kinh khủng.
dùng1717828

Wow, điều này thật tuyệt vời. Không biết điều này (và có lẽ sẽ không sử dụng nó nhiều, vì tôi nghĩ rằng nó đi ngược lại Quy tắc rõ ràng ) nhưng thật tuyệt khi biết điều đó! Câu hỏi, mặc dù: Tại sao không gian khi bắt đầu exdir? (Có phải đó chỉ để căn chỉnh vì lý do thẩm mỹ?)
Wildcard

2
@ Thẻ con : 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 "$@". Làm điều đó với aliasescho phép bạn sử dụng các bản mở rộng của các mẫu một cách trực tiếp và an toàn hơn. Bạn cần một bối cảnh thứ hai với evalkhi được gọi từ bên trong một chức năng, nhưng nó không thực sự không an toàn miễn là tên patternlistđược điều khiển bởi bạn. Chúng chỉ có thể phá vỡ trong hầu hết các trường hợp ngay cả khi chúng không trừ khi một số kẻ tấn công cố tình kết thúc chính xác của bạn case.
mikeerv

1
Tôi sử dụng mẫu này trong .bashrc: alias sudo='sudo ', điều này cho phép tôi gọi tất cả các lệnh bí danh của mình sau a sudo. Không có không gian, nó sẽ không hoạt động
arainone

1
@Wildcard - Tôi không chính xác ủng hộ việc sử dụng như vậy, nhưng đó là sự thật bạn có thể, và cũng đúng là bạn phải có ít nhất một chút điên rồ để thử.
mikeerv

2

Một chức năng là một lựa chọn tốt hơn so với một bí danh có thể mở rộng ở đây.

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

Bằng cách đó, bạn có hai tùy chọn để thêm tùy chọn vào môi trường:

  • Sửa đổi grep_optionsmảng; điều này hỗ trợ chính xác các tùy chọn với khoảng trắng, ký tự toàn cầu và các trường hợp góc khác:

    grep_options+=( --exclude-dir=classes --exclude-dir='*/.sass-cache' )
  • Sử dụng GREP_OPTIONSbiến vô hướng truyền thống , bất chấp những cạm bẫy của nó (xem BashFAQ # 50 để hiểu một số trong số này):

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

Điều đó nói rằng, nếu bạn muốn các tùy chọn của mình được phản ánh bởi các grepthể hiện được gọi bên ngoài trình bao, thì cả bí danh và hàm sẽ không thực hiện. Thay vào đó, bạn sẽ muốn một tập lệnh bao bọc được đặt sớm hơn trong PATH của bạn so với greplệnh thực . Ví dụ:

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

... và, trong ~/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} "$@"
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.