Làm thế nào để chạy một bí danh trong một kịch bản shell?


101

Tôi có một tập tin thực thi mpiexec, có đường dẫn đầy đủ ~/petsc-3.2-p6/petsc-arch/bin/mpiexec. Vì tôi muốn thực thi lệnh này trong các thư mục khác nhau (mà không phải nhập lại toàn bộ đường dẫn), tôi thiết lập bí danh trong .bashrctệp nhà của mình :

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

cho phép tôi thực hiện mpiexectập tin này tại dấu nhắc lệnh một cách dễ dàng bằng cách gõ:

petsc myexecutable

Tôi đã cố gắng viết một tập tin shell shell, được đặt tên script, sử dụng bí danh mới của tôi petsclàm lệnh. Sau khi cấp cho tập lệnh shell của tôi các quyền thích hợp (sử dụng chmod), tôi đã thử chạy tập lệnh. Tuy nhiên, nó đã cho tôi lỗi sau:

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

Tôi biết rằng tôi chỉ có thể viết đường dẫn đầy đủ vào mpiexectệp, nhưng thật khó khăn khi viết đường dẫn đầy đủ mỗi khi tôi muốn viết một tập lệnh mới. Có cách nào để tôi có thể sử dụng bí danh của mình petsctrong tệp script không? Có cách nào để tôi có thể chỉnh sửa .bashrchoặc .bash_profilethực hiện điều này không?


Làm thế nào về việc thêm bí danh .bash_aliases? Ngoài ra, về cách đặt bí danh đường dẫn tuyệt đối thay vì đường dẫn tương đối nhưalias petsc='/home/user/petsc-3.2-p6/petsc-arch/bin/mpiexec'
Nitin Venkatesh

@nitstorm: Cả hai giải pháp dường như không hoạt động ... Tôi vẫn nhận được lỗi tương tự như trước đây
Paul

Câu trả lời:


74
  1. Trong kịch bản shell của bạn sử dụng đường dẫn đầy đủ thay vì bí danh.

  2. Trong tập lệnh shell của bạn, đặt một biến, cú pháp khác nhau

    petsc='/home/your_user/petsc-3.2-p6/petsc-arch/bin/mpiexec'
    
    $petsc myexecutable
  3. Sử dụng một chức năng trong kịch bản của bạn. Có lẽ tốt hơn nếu petscphức tạp

    function petsc () {
        command 1
        command 2
    }
    
    petsc myexecutable
  4. Nguồn bí danh của bạn

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

Bạn có thể không muốn tìm nguồn của mình .bashrc, vì vậy, IMO, một trong 3 đầu tiên sẽ tốt hơn.


16
Điểm 4 không hoạt động, trừ khi bạn sử dụng shopt -s expand_aliasestrong cùng một kịch bản.
enzotib

Đề xuất của bạn 2) hoạt động, nhưng tôi muốn có thể sử dụng cùng một lệnh trong nhiều tập lệnh shell mà không phải viết dòng đầu tiên petc = "...". Có cách nào để làm việc này không?
Paul

1
@enzotib - cảm ơn bạn, tôi đã thêm nó vào câu trả lời của tôi.
Panther

1
Trong điểm 2, bạn không đặt bí danh mà là một biến.
pabouk

1
Không được OP yêu cầu nhưng có liên quan đến tiêu đề câu hỏi: Điểm 2 sẽ không hoạt động với các lệnh chứa |. Ở đây, sử dụng shopt -s expand_aliases& bí danh cục bộ, ví dụ alias myalias='echo abc|rev'- yêu cầu ngắt dòng trước khi sử dụng (xem ALIASES in man bash). Điểm 4: Tệp có thể ngăn chặn việc thực thi không tương tác, tức là trong một tập lệnh. Tìm sớm exithoặc return, ví dụ [ -z "$PS1" ] && return(kiểm tra nếu dấu nhắc chính không được đặt chỉ ra vỏ không tương tác) hoặc có thể có kiểm tra itrong $-( $-chứa tùy chọn vỏ, icó nghĩa là tương tác). Xem man bashcho các biến.
hợp lệ

61

Bí danh không được ủng hộ cho các hàm shell. Từ bashtrang hướng dẫn:

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

Để tạo một hàm và xuất nó thành các lớp con, hãy đặt các mục sau vào ~/.bashrc:

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

Sau đó, bạn có thể tự do gọi lệnh của bạn từ các kịch bản của bạn.


Điều đó gần như hoạt động ... vấn đề duy nhất là tôi cần có thể chuyển các cờ khác nhau cho "mpiexec" có thể thực thi được ... Ví dụ, tôi cần có khả năng thực thi một cái gì đó như "petc -n 40 myexecutable" với bí danh "petc"
Paul

4
@Paul: Tôi đã thêm "$@"chỉ để xử lý các đối số.
enzotib

12

Các hàm và bí danh của Shell được giới hạn trong trình bao và không hoạt động trong các tập lệnh shell được thực thi. Lựa chọn thay thế cho trường hợp của bạn:

  • (nếu bạn không bận tâm sử dụng mpiexecthay vì petsc) Thêm $HOME/petsc-3.2-p6/petsc-arch/binvào PATHbiến của bạn . Điều này có thể được thực hiện bằng cách chỉnh sửa ~/.profilevà nối thêm:

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

    Đăng nhập lại để áp dụng những thay đổi này

  • Tạo thư mục ~/bin

    • tạo một tập lệnh bao bọc có tên petsc:

      #!/bin/sh
      exec ~/petsc-3.2-p6/petsc-arch/bin/mpiexec "$@"
    • nếu chương trình cho phép, bạn có thể bỏ qua shellscript và tạo symlink bằng lệnh:

      ln -s ~/petsc-3.2-p6/petsc-arch/bin/mpiexec ~/bin/petsc

9

Trong bash 4, bạn có thể sử dụng biến đặc biệt : $BASH_ALIASES.

Ví dụ:

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

Hoặc định nghĩa là biến sau đó sử dụng thay thế lệnh hoặc eval.

Vì vậy, ví dụ, thay vì xác định bí danh, chẳng hạn như:

alias foo="echo test"

định nghĩa nó là:

foo="echo test"

thay thế. Sau đó thực hiện nó bằng một trong hai cách sau:

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

hoặc là:

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

Các bí danh rõ ràng không được ủng hộ cho các hàm shell, câu trả lời này là câu duy nhất nên được chấp nhận. Ngay cả Debian 8 cũ cũng có phiên bản bash 4, vì vậy đây ${BASH_ALIASES[alias]}là một lựa chọn tốt. Nếu không, tôi đã phải chỉnh sửa rất nhiều dòng .bash_aliases của mình để áp dụng những thứ khác. Cảm ơn bạn.
erm3nda

8

Bạn có thể buộc bash thực thi tập lệnh của mình dưới dạng trình bao tương tác với cờ -i. Điều này sẽ cho biết tệp .bashrc của bạn để xác định bí danh và các hàm khác.

Thí dụ:

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

Thêm thông tin:

$ man bash

2
.bashrccũng được đọc trong quá trình thực thi lệnh SSH không tương tác (đó là lý do tại sao nó có kiểm tra tính tương tác ở trên cùng)
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).

Vì vậy, câu trả lời thực sự cho câu hỏi này, đối với những người muốn sử dụng bí danh thực tế trong các tập lệnh shell thay vì các lựa chọn thay thế cho chúng, là:

#!/bin/bash

shopt -s expand_aliases

alias foo=bar

foo whatever

Về lý do tại sao tôi muốn làm điều này: Do hoàn cảnh bất thường, tôi cần lừa Dockerfile nghĩ rằng đó là một kịch bản shell.


4
  1. Trong .bash_aliases:

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

    Hoặc đặt chức năng trong .bashrc. Thông thường .bashrcchỉ trong cài đặt cấu hình bashđược lưu trữ.

  2. Trong thiết bị đầu cuối: source .bash_aliases

  3. Gọi nó đi: petsc arg(s)

Ưu điểm: bạn không cần phải export -f petsc.bash_aliases. Bí danh không được dùng nữa nhưng sử dụng .bash_aliasescho các chức năng là ok.


Tôi thích giải pháp này, tôi sẽ thử lại sau
Greenonline

2
  1. Sử dụng bí danh của bạn trong kịch bản shell của bạn.
  2. Nguồn kịch bản của bạn trong shell tương tác hiện tại của bạn thay vì thực thi nó.

Vì vậy, nếu bạn có một tệp được gọi script.shbằng các lệnh bao gồm sử dụng bí danh, chỉ cần gõ:

source script.sh

@DavidFoerster Phương pháp này hoạt động tốt. Tìm kiếm một tập lệnh với .hoặc sourcebuiiltin làm cho trình bao hiện tại thực thi tất cả các lệnh trong nó. Nếu mở rộng bí danh sẽ xảy ra trong shell trong đó .hoặc sourceđang chạy, nó xảy ra. Tuy nhiên, điều quan trọng là phải nhận ra rằng phương pháp này đôi khi chỉ hữu ích, bởi vì thường người ta cần hoặc muốn thực thi một tập lệnh trong vỏ của chính nó, với môi trường riêng của nó. Các tập lệnh Shell được viết với ý định được thực thi theo cách thông thường thường không nên có nguồn gốc - chúng thường không hoạt động đúng.
Eliah Kagan

@EliahKagan: Cảm ơn. Bây giờ tôi hiểu câu trả lời có nghĩa là gì. Tôi sẽ thêm một lời giải thích.
David Foerster

1

(EDIT: đã xóa các chức năng kể từ khi tôi đọc sai cách gọi của mpiexec.)

Nếu điều duy nhất bạn cần là ít gõ, tại sao bạn không đặt thư mục vào $ PATH? Hoặc tạo một liên kết tượng trưng đến mpiexec từ một số thư mục trong $ PATH? Hoặc (yêu thích của tôi) đặt bí danh trong một tập lệnh mà bạn nguồn trong tập lệnh gọi?


1
Lý do tại sao tôi không thể đặt nó vào $ PATH của mình là vì tôi có một tệp 'mpiexec' khác trong một thư mục khác có giá trị trong $ PATH của tôi. Nếu tôi thêm đường dẫn đến 'mpiexec' mới này, có lẽ nó sẽ cố gắng thực thi cả hai ... phải không?
Paul

1
Không thể hiểu tại sao không chỉ đơn giản là sử dụng "$@".
enzotib

2
Paul, nó sẽ cố gắng thực hiện cái đầu tiên trong PATH chứ không phải cả hai.
unhammer

enzotib, ah Tôi đã đọc sai cách gọi mpiexec, tôi nghĩ rằng nó cần tất cả các đối số như một. Sẽ chỉnh sửa câu trả lời của tôi :)
unhammer
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.