Tại sao một lệnh từ xa SSH nhận được ít biến môi trường hơn khi chạy thủ công? [đóng cửa]


239

Tôi có một lệnh chạy tốt nếu tôi ssh đến một máy và chạy nó, nhưng không thành công khi tôi cố chạy nó bằng lệnh ssh từ xa như:

ssh user@IP <command>

So sánh đầu ra của "env" bằng cả hai phương thức nối lại trong các môi trường khác nhau. Khi tôi đăng nhập thủ công vào máy và chạy env, tôi sẽ nhận được nhiều biến môi trường hơn sau đó khi tôi chạy:

ssh user@IP "env"

Bất cứ ý tưởng tại sao?


30
Tại sao chính xác câu hỏi này đóng cửa như lạc đề?
jottr

13
Có lẽ bởi vì nó không liên quan đến lập trình. Nó đã được chuyển đến Super User thay vì đóng.
Daniel H

8
bashkhông phải là một ngôn ngữ kịch bản?
Dan Nissenbaum

Trong Debian 8 tôi đã phải thay đổi shell thành bash trong / etc / passwd vì một số lý do. Ngay cả dashfigurung dash để cho / bin / sh trỏ đến bash cũng không giúp được gì.
dùng1050755

Câu trả lời:


173

Có nhiều loại vỏ khác nhau. Shell thực thi lệnh SSH là một shell không tương tác, trong khi shell thông thường của bạn là shell đăng nhập hoặc shell tương tác. Mô tả sau đây, từ người đàn ông bash:

       Một shell đăng nhập là một cái có ký tự đầu tiên của đối số
       zero là một - hoặc một bắt đầu với tùy chọn --login.

       Một vỏ tương tác được bắt đầu mà không có tùy chọn
       đối số và không có tùy chọn -c có đầu vào tiêu chuẩn
       và lỗi đều được kết nối với thiết bị đầu cuối (như đã xác định
       bằng isatty (3)) hoặc bắt đầu bằng tùy chọn -i. PS1 là
       đặt và $ - bao gồm i nếu bash tương tác, cho phép
       shell script hoặc một tập tin khởi động để kiểm tra trạng thái này.

       Các đoạn sau mô tả cách bash thực thi
       tập tin khởi động. Nếu bất kỳ tập tin nào tồn tại nhưng không thể
       đọc, bash báo lỗi. Dấu ngã được mở rộng trong tệp
       tên như được mô tả dưới đây dưới Tilde Expansion trong
       Phần mở rộng.

       Khi bash được gọi như một vỏ đăng nhập tương tác, hoặc như
       một vỏ không tương tác với tùy chọn --login, nó đầu tiên
       đọc và thực thi các lệnh từ tệp / etc / profile, nếu
       tập tin đó tồn tại Sau khi đọc tập tin đó, nó tìm kiếm
       ~ / .bash_profile, ~ / .bash_login và ~ / .profile, trong đó
       thứ tự, và đọc và thực thi các lệnh từ cái đầu tiên
       tồn tại và có thể đọc được. Tùy chọn --noprofile có thể
       được sử dụng khi vỏ được bắt đầu để ức chế hành vi này
       ior

       Khi shell đăng nhập thoát, bash đọc và thực thi các lệnh
       từ tệp ~ / .bash_logout, nếu nó tồn tại.

       Khi shell tương tác không phải là shell đăng nhập là
       đã bắt đầu, bash đọc và thực thi các lệnh từ ~ / .bashrc,
       nếu tập tin đó tồn tại Điều này có thể bị ức chế bằng cách sử dụng
       --norc tùy chọn. Tùy chọn tệp --rcfile sẽ buộc bash
       để đọc và thực thi các lệnh từ tệp thay vì
       ~ / .bashrc.

       Khi bash được bắt đầu không tương tác, để chạy shell
       tập lệnh, ví dụ, nó tìm biến BASH_ENV trong
       môi trường, mở rộng giá trị của nó nếu nó xuất hiện ở đó,
       và sử dụng giá trị mở rộng làm tên của tệp để đọc
       và thực hiện. Bash hành xử như thể lệnh sau
       Đã được thực hiện:
              nếu [-n "$ BASH_ENV"]; sau đó . "$ BASH_ENV"; fi
       nhưng giá trị của biến PATH không được sử dụng để tìm kiếm
       cho tên tập tin.


7
Câu trả lời tuyệt vời, đây chính xác là vấn đề, các biến môi trường cần thiết nằm trong / etc / bashrc, không có nguồn gốc trong chế độ không tương tác. Di chuyển chúng đến / etc / profile đã giải quyết vấn đề. Cảm ơn rât nhiều!
Tom Feiner

1
Câu trả lời này chỉ trong một giải pháp một phần. Dưới đây là một số thông tin khác: thêm một biến môi trường khác (ví dụ: xuất SOURCED_SYIUS_ETC_BASHRC) vào các tệp khác nhau có nguồn gốc: / etc / profile, etc / bashrc, ~ / .profile, ~ / .bash_profile, ~ / bashrc. Sau đó tìm kiếm biến duy nhất đó trong đầu ra Jenkins. Trong trường hợp của tôi, tôi đã cập nhật / etc / bashrc để chứa 'export SOURCED_SYIUS_ETC_BASHRC = yes' và biến đó xuất hiện trong nhật ký Jenkins cho nút. Vì vậy, trong trường hợp của tôi, để đặt các biến môi trường cho nô lệ jenkins, họ phải truy cập vào / etc / bashrc. Jenkins ssh chỉ đăng nhập nguồn gốc / etc / bashrc.
Coder Roadie

Sửa lỗi: Ý tôi là /etc/bash.bashrc, không phải / etc / bashrc.
Roadie

37
Đó là một bức tường văn bản, tôi nghĩ rằng sẽ đáng để làm nổi bật nó ssh user@host "bash --login -c 'command arg1 ...'"sẽ làm cho trình điều khiển từ xa thiết lập môi trường đăng nhập. Phần bạn trích dẫn không đề cập đến --loginnhưng sẽ dễ dàng bỏ qua điều này.
tiền mã hóa

Cảm ơn bạn về bài đăng này, tôi đã từng ssh <ssh options> <IP> bash --login my_script.shchạy một kịch bản trên máy từ xa, xử lý và cho phép tôi sử dụng thành công các vv env cục bộ nhưJAVA_HOME
markc

117

Làm thế nào về việc tìm nguồn cung cấp hồ sơ trước khi chạy lệnh?

ssh user@host "source /etc/profile; /path/script.sh"

Bạn có thể tìm thấy nó tốt nhất để thay đổi điều đó để ~/.bash_profile, ~/.bashrchoặc bất cứ điều gì.

(Như ở đây (linuxquestions.org) )


1
Có vấn đề này, giải pháp này đã làm việc tuyệt vời.
Sam52

10
Phải luôn luôn gõ mã bổ sung chỉ để nguồn môi trường là vô lý!
Michael

4
Người ta hiếm khi lặp đi lặp lại các loại điều này, thông thường nó sẽ nằm trong một tập lệnh, và như vậy, không quan trọng là có bao nhiêu "mã bổ sung", miễn là nó hoạt động: tm:
Ian Vaughan

1
Nếu tôi nguồn cả / etc / profile và ~ / .bash_profile (để có được bổ sung của người dùng vào đường dẫn) thì nó hoạt động, nhưng nó thật xấu. Phải có một cách dễ dàng hơn để nói lệnh (trong trường hợp của tôi là xterm) sử dụng thông tin đăng nhập "tương tác" và kết thúc với đường dẫn cụ thể của người dùng trên máy từ xa?
Jess

ssh $ 1 "nguồn ~ / .bashrc; ~ / temp_unix.sh" Ở đây temp_unix.sh đã xuất MANI_HOME = "mani deepak" nhưng nó không hoạt động.
mani deepak

90

Môi trường Shell không tải khi chạy lệnh ssh từ xa. Bạn có thể chỉnh sửa tập tin môi trường ssh:

vi ~/.ssh/environment

Định dạng của nó là:

VAR1=VALUE1
VAR2=VALUE2

Ngoài ra, kiểm tra sshdcấu hình cho PermitUserEnvironment=yestùy chọn.


1
sự hoàn hảo! +100 nếu tôi có thể :)
Dexter

VisualGDB đã thất bại với lỗi "bash: gcc: không tìm thấy lệnh" và giải pháp này đã khắc phục điều đó.
KalenGi

tuyệt diệu. ước gì tôi đã biết về điều này những năm trước.
trọng lực

Đây là câu trả lời hoàn hảo!
Jirapong

1
@ pg2455 trong khi bạn không phải lúc nào cũng có thể định cấu hình sshd trên máy chủ của mình (hoặc không muốn bật nó cho tất cả), bạn vẫn có thể chỉnh sửa môi trường người dùng của mình
dpedro 19/03/19

63

Tôi đã có vấn đề tương tự, nhưng cuối cùng tôi phát hiện ra rằng ~ / .bashrc là tất cả những gì tôi cần.

Tuy nhiên, trong Ubuntu, tôi đã phải nhận xét dòng ngừng xử lý ~ / .bashrc:

#If not running interactively, don't do anything
[ -z "$PS1" ] && return

8
Ngoài ra, bạn chỉ có thể đặt tất cả mã "không tương tác" của mình lên trên dòng đó.
máy

đẹp, tiết kiệm cho tôi rất nhiều thời gian :) cảm ơn
Lance Pollard

Cảm ơn. Chỉ cần thêm rằng tập tin với câu lệnh return có thể được tìm thấy tại /etc/bash.bashrc.
adarshr

Có cách nào để bỏ qua mã này trong máy chủ mà không thay đổi nó không?
Yoni

Tôi đã dành rất nhiều thời gian để cố gắng hiểu tại sao kịch bản của tôi không hoạt động. Ai nghĩ rằng đó là một ý tưởng tốt để đặt những dòng này trong .bashrc ???
Sharcoux

4

Tôi thấy một giải pháp dễ dàng cho vấn đề này là thêm nguồn / etc / profile vào đầu tập tin script.sh mà tôi đang cố chạy trên hệ thống đích. Trên các hệ thống ở đây, điều này khiến cho các biến môi trường mà script.sh cần được cấu hình như thể đang chạy từ shell đăng nhập.

Trong một trong những phản hồi trước đó, có ý kiến ​​cho rằng ~ / .bashr_profile v.v ... được sử dụng. Tôi đã không dành nhiều thời gian cho việc này, nhưng vấn đề với điều này là nếu bạn ssh với một người dùng khác trên hệ thống đích hơn là hệ vỏ trên hệ thống nguồn mà bạn đăng nhập thì có vẻ như điều này gây ra cho người dùng hệ thống nguồn Tên được sử dụng cho ~.


Hoàn hảo! Giải pháp một dòng tốt đẹp cho vấn đề.
corpico

3

Chỉ cần xuất các biến môi trường bạn muốn phía trên kiểm tra cho trình bao không tương tác trong ~ / .bashrc.

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.