Bí danh phạm vi trong các hàm bash


9

Tôi sử dụng một tập lệnh (mà tôi không có quyền truy cập ghi) để tạo ra một loạt các bí danh để thiết lập một môi trường. Tôi muốn tạo một hàm bash để thiết lập môi trường của mình, nhưng có vẻ như các bí danh không tồn tại với thân hàm.

Đây là một ví dụ tối thiểu:

# aliases.sh
alias fooAlias='echo "this will never work!"'  

.

# .bashrc
function setupLotsOfThings() {
    source aliases.sh
    fooAlias
}

.

Bây giờ, nếu tôi chỉ đơn giản là nguồn aliases.shtương tác, mọi thứ hoạt động như mong đợi:

[mycomputer]~/ $ source aliases.sh
[mycomputer]~/ $ fooAlias
this will never work!

Tuy nhiên, nếu tôi gọi hàm được định nghĩa trong .bashrc của mình, thì nó không nhận ra bí danh sau khi tìm nguồn gốc định nghĩa của nó:

[mycomputer]~/ $ setupLotsOfThings
-bash: fooAlias: command not found

Chuyện gì đang xảy ra ở đây? Có điều gì tôi đang thiếu về phạm vi của aliaslệnh khi được sử dụng trong một hàm không?

Chỉnh sửa: Tôi sẽ thêm một số chi tiết ngoài ví dụ tối thiểu để làm sáng tỏ những gì tôi đang cố gắng thực hiện.

Đối với công việc của tôi, tôi phát triển và chạy rất nhiều phần mềm trên một cụm và / hoặc lưới. Tôi có một số dự án yêu cầu các môi trường hoàn toàn khác nhau, chẳng hạn như các phiên bản gcc khác nhau, bản phát hành phần mềm cụ thể, PATH cấu hình và dữ liệu và các biến môi trường khác nhau. Quản trị viên cung cấp các tập lệnh để thiết lập nhiều thứ khác nhau, thường là bằng cách xác định các hàm shell hoặc bí danh, gọi các hàm hoặc bí danh khác hoặc chạy các tập lệnh khác nhau. Đối với tôi, đó là một hộp đen.

Tôi muốn thiết lập các môi trường khác nhau của riêng tôi với một lệnh duy nhất. Hiện tại, tôi làm một cái gì đó như:

[mycomputer]~/ $ source /some/environment/setup/script.sh
[mycomputer]~/ $ aliasToSetupSomeSoftwareVersion    #this was defined in the above
[mycomputer]~/ $ anotherAliasForOtherSoftware
[mycomputer]~/ $ source /maybe/theres/another/script.sh
[mycomputer]~/ $ runSomeOtherSetup      # this was defined in the new script

Các lệnh này thường phải được chạy theo thứ tự. Ý tưởng của tôi về cơ bản là chỉ sao chép các dòng trên vào một khối chức năng, nhưng như ví dụ ban đầu cho thấy, đơn giản là nó không hoạt động. Giải pháp thay thế được chào đón nhiều hơn!

Câu trả lời:


10

Một giải pháp thay thế là dán các lệnh đó vào tệp văn bản thay vì khối chức năng. Cái gì đó như:

## This is needed to make the sourced aliases available
## within the script.
shopt -s expand_aliases

source /some/environment/setup/script.sh
aliasToSetupSomeSoftwareVersion
anotherAliasForOtherSoftware
source /maybe/theres/another/script.sh
runSomeOtherSetup

Lưu nó như setup1.shbất cứ nơi nào bạn muốn. Bí quyết là sau đó nguồn tệp này, không thực hiện nó:

$ source setup1.sh

Điều đó sẽ chạy các bí danh có trong kịch bản và cũng làm cho chúng có sẵn cho trình bao hiện tại của bạn.

Bạn có thể đơn giản hóa thêm quy trình bằng cách thêm phần này vào .bashrc:

alias setupLotsOfThings="source setup1.sh"

Bây giờ bạn có thể chỉ cần chạy setupLotsOfThingsvà nhận hành vi bạn muốn từ hàm.


Giải trình

Có hai vấn đề ở đây. Đầu tiên, các bí danh không có sẵn cho hàm mà chúng được khai báo nhưng chỉ một khi hàm đó đã thoát và thứ hai là các bí danh không có sẵn trong các tập lệnh. Cả hai đều được giải thích trong cùng một phần của man bash:

Các bí danh không được mở rộng khi shell không tương tác, trừ khi tùy chọn shell extend_aliases được đặt bằng shopt (xem mô tả về shopt trong SHELL BUILTIN THÔNG TIN bên dưới).

Các quy tắc liên quan đến định nghĩa và sử dụng bí danh có phần khó hiểu. Bash luôn đọc ít nhất một dòng đầu vào hoàn chỉnh trước khi thực hiện bất kỳ lệnh nào trên dòng đó. Các bí danh được mở rộng khi một lệnh được đọc, không phải khi nó được thực thi. Do đó, một định nghĩa bí danh xuất hiện trên cùng một dòng với một lệnh khác không có hiệu lực cho đến khi dòng đầu vào tiếp theo được đọc. Các lệnh theo định nghĩa bí danh trên dòng đó không bị ảnh hưởng bởi bí danh mới. Hành vi này cũng là một vấn đề khi các chức năng được thực thi. Các bí danh được mở rộng khi một định nghĩa hàm được đọc, không phải khi hàm được thực thi, bởi vì một định nghĩa hàm tự nó là một lệnh ghép. Kết quả là, các bí danh được xác định trong một hàm không
có sẵn cho đến sau khi hàm đó được thực thi.
Để an toàn, luôn đặt các định nghĩa bí danh trên một dòng riêng biệt và không sử dụng bí danh trong các lệnh com pound.

Sau đó, có sự khác biệt giữa thực thi và tìm nguồn cung cấp một tệp. Về cơ bản, việc chạy một kịch bản làm cho nó chạy trong một shell riêng trong khi tìm nguồn cung cấp cho nó chạy trong shell hiện tại. Vì vậy, tìm nguồn cung ứng setup.shlàm cho các bí danh có sẵn cho shell cha trong khi thực thi nó như là một kịch bản sẽ không.


Chà, tôi đang làm việc trên một cụm và có sẵn một số tập lệnh "bí danh" như vậy để giúp thiết lập môi trường phần mềm, v.v ... Tập lệnh bí danh xác định nhiều bí danh khác nhau; Mục tiêu của tôi là gọi một môi trường cụ thể bằng cách tìm nguồn gốc các bí danh chính xác, và sau đó chạy (một số) các bí danh đó. Tôi thà làm điều này trong một lệnh duy nhất, hơn là phải chạy một số lệnh theo trình tự.
đuổi theo

Và PS, kịch bản thiết lập các bí danh không may là rất dài dòng và hơi chậm (vì nó chạm vào nhiều tệp trên NFS), vì vậy tôi không muốn tìm tất cả những thứ này, ví dụ như tại thời điểm đăng nhập.
đuổi theo

@chase nhưng chúng chỉ có nguồn gốc khi bạn chạy setupLotsOfThings, chúng chỉ không có sẵn cho chức năng. Chúng hoạt động o vỏ bạn gọi là hàm từ. Dù sao, nếu chức năng của bạn chỉ nguồn bí danh tại sao không chỉ sử dụng một bí danh? Ví dụ : alias setupstuff="source aliases.sh".
terdon

đúng, nhưng tôi không lo lắng về phạm vi mỗi se . Lý tưởng nhất là tôi chỉ muốn kết hợp "công cụ nguồn" và "bí danh chạy" thành một. Có lẽ nó có thể được thực hiện với 3 chức năng? hàm sourceStuff () {source ...}; hàm runStuff () {someAlias; ...}; chức năng setupLotsOfThings () {sourceStuff; runStuff; };
đuổi theo

@chase yeah, tôi đã nghĩ vậy nhưng nó không hoạt động :). Bạn có thể mở rộng câu hỏi của bạn với một số chi tiết bạn cần làm không? Các hàm chỉ có thể xử lý rất phức tạp, thay vào đó bạn có thể phải viết một đoạn script nhỏ.
terdon

7

Trên thực tế, bí danh của bạn có sẵn sau khi chức năng được tải! Bạn có thể sử dụng chúng trong shell tương tác của bạn hoặc trong của bạn .bashrcsau khi thực hiện chức năng.

Hạn chế là các bí danh trong định nghĩa hàm được mở rộng khi định nghĩa hàm được đọc, không phải khi hàm được ước tính. Đây là một hạn chế của bash. Vì vậy, điều này sẽ làm việc:

function setupLotsOfThings() {
    source aliases.sh
}
setupLotsOfThings
fooAlias

Nhưng không phải cái này:

function setupLotsOfThings() {
    source aliases.sh
}
function useTheAliases() {
    fooAlias
}
setupLotsOfThings
useTheAliases

Nếu bạn cần các bí danh có thể sử dụng được bên trong các hàm và có thể được xác định sau khi hàm được phân tích cú pháp, thay vào đó hãy tạo các hàm đó. Hãy nhớ rằng bạn có thể sử dụng commandnội dung để gọi một lệnh bên ngoài từ một hàm cùng tên.

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.