ความแตกต่างระหว่างล็อกอินเชลล์และเชลล์ที่ไม่ใช่ล็อกอิน?


318

ฉันเข้าใจถึงความแตกต่างพื้นฐานระหว่างเชลล์แบบโต้ตอบและเชลล์แบบไม่โต้ตอบ แต่สิ่งที่แตกต่างกันอย่างแท้จริงของเปลือกเข้าสู่ระบบจากเปลือกไม่ใช่ - เข้าสู่ระบบ?

คุณสามารถให้ตัวอย่างสำหรับการใช้งานของเปลือกโต้ตอบที่ไม่ได้เข้าสู่ระบบได้หรือไม่?


45
ฉันคิดว่าคำถามนี้เป็นประโยคที่ดีกว่าเพราะ " ทำไม / เราควรแยกความแตกต่างของการเข้าสู่ระบบและที่ไม่ใช่การเข้าสู่ระบบ?" หลายแห่งบนเว็บบอกเราแล้วว่าอะไรคือความแตกต่างในแง่ของไฟล์เริ่มต้นแต่ละไฟล์ที่อ่าน แต่ดูเหมือนว่าจะไม่มีใครตอบว่า "ทำไม" อย่างน่าพอใจและน่าเชื่อถือ ตัวอย่างกรณีการใช้งานที่คุณไม่ต้องการอย่างใดอย่างหนึ่งหรือพฤติกรรมอื่นจะดี
Kal

2
@Kal นี้จะต้องเป็นคำถามที่แตกต่างกันเนื่องจากไม่มีคำตอบที่นี่จริงครอบคลุมที่ แก้ไข: จริงแล้วนี่คือ: ทำไมเชลล์ล็อกอินเหนือเชลล์ที่ไม่ใช่ล็อกอิน ? .
Skippy le Grand Gourou

คำตอบ:


304

ล็อกอินเชลล์เป็นกระบวนการแรกที่ดำเนินการภายใต้ ID ผู้ใช้ของคุณเมื่อคุณเข้าสู่ระบบสำหรับเซสชันแบบโต้ตอบ กระบวนการเข้าสู่ระบบบอกให้เปลือกทำงานเป็นเปลือกเข้าสู่ระบบด้วยการประชุม: ผ่านการโต้แย้ง 0 ซึ่งโดยปกติจะเป็นชื่อของเปลือกที่ปฏิบัติการได้ด้วย-ตัวอักษรที่เตรียมไว้ (เช่น-bashในขณะที่มันจะเป็นปกติbashเปลือกหอยเข้าสู่ระบบโดยทั่วไปอ่านไฟล์ที่ สิ่งเช่นการตั้งค่าตัวแปรสภาพแวดล้อม: /etc/profileและ~/.profileสำหรับแบบดั้งเดิมบอร์นเปลือก~/.bash_profileนอกจากนี้สำหรับทุบตี , /etc/zprofileและ~/.zprofileสำหรับ zsh , /etc/csh.loginและ~/.loginสำหรับ csh ฯลฯ

เมื่อคุณเข้าสู่ระบบในคอนโซลข้อความหรือผ่าน SSH หรือด้วยsu -คุณจะได้รับเปลือกเข้าสู่ระบบแบบโต้ตอบ เมื่อคุณเข้าสู่ระบบในโหมดกราฟิก (บนตัวจัดการการแสดงผล X ) คุณจะไม่ได้รับเชลล์การเข้าสู่ระบบ แต่คุณจะได้รับตัวจัดการเซสชันหรือตัวจัดการหน้าต่างแทน

มันยากที่จะเรียกใช้ล็อกอินเชลล์แบบไม่โต้ตอบแต่การตั้งค่า X บางอย่างทำเมื่อคุณเข้าสู่ระบบด้วยเครื่องมือจัดการการแสดงผลเพื่อจัดเรียงเพื่ออ่านไฟล์โปรไฟล์ การตั้งค่าอื่น ๆ (ขึ้นอยู่กับการกระจายและการจัดการการแสดงผล) อ่าน/etc/profileและ~/.profileชัดเจนหรือไม่อ่าน อีกวิธีหนึ่งในการรับเชลล์ล็อกอินแบบไม่โต้ตอบคือการล็อกอินแบบรีโมตโดยใช้คำสั่งที่ส่งผ่านอินพุตมาตรฐานซึ่งไม่ใช่เทอร์มินัลเช่นssh example.com <my-script-which-is-stored-locally(ตรงกันข้ามกับssh example.com my-script-which-is-on-the-remote-machineซึ่งรันเชลล์ที่ไม่ใช่แบบโต้ตอบและไม่ใช่ล็อกอิน)

เมื่อคุณเริ่มเชลล์ในเทอร์มินัลในเซสชันที่มีอยู่ (หน้าจอ, เทอร์มินัล X, เทอร์มินัลบัฟเฟอร์ Emacs, เชลล์ภายในเชลล์อื่น ฯลฯ ) คุณจะได้รับเชลล์แบบโต้ตอบและไม่ใช่การเข้าสู่ระบบ เชลล์ที่อาจจะอ่านแฟ้มการกำหนดค่าเปลือก ( ~/.bashrcสำหรับทุบตีเรียกว่าเป็นbash, /etc/zshrcและ~/.zshrcสำหรับ zsh, /etc/csh.cshrcและ~/.cshrcสำหรับ csh แฟ้มที่ระบุโดยENVตัวแปรสำหรับเปลือกหอย POSIX / XSI สอดคล้องเช่นประ ksh และทุบตีเมื่อเรียกเป็นsh, $ENVถ้าตั้งค่าและ~/.mkshrcสำหรับ mksh ฯลฯ )

เมื่อเปลือกรันสคริปต์หรือคำสั่งผ่านในบรรทัดคำสั่งของมันก็เป็นไม่โต้ตอบไม่เข้าสู่ระบบเปลือก เชลล์ดังกล่าวทำงานตลอดเวลา: เป็นเรื่องธรรมดามากที่เมื่อโปรแกรมเรียกโปรแกรมอื่นมันรันสคริปต์เล็ก ๆ ในเชลล์เพื่อเรียกใช้โปรแกรมอื่น เชลล์บางตัวอ่านไฟล์เริ่มต้นในกรณีนี้ (ทุบตีรันไฟล์ที่ระบุโดยBASH_ENVตัวแปร, zsh รัน/etc/zshenvและ~/.zshenv), แต่สิ่งนี้มีความเสี่ยง: เชลล์สามารถถูกเรียกใช้ในทุกประเภทของบริบทและแทบจะไม่สามารถทำอะไรได้เลย ทำลายบางสิ่งบางอย่าง

ฉันลดความซับซ้อนลงเล็กน้อยดูคู่มือสำหรับรายละเอียดเต็มไปด้วยเลือด


2
คุณช่วยยกตัวอย่างวิธีการใช้งานbashเป็นเชลล์ล็อกอินแบบไม่โต้ตอบได้หรือไม่?
Piotr Dobrogost

13
@PiotrDobrogostecho $- | bash -lx
Gilles

1
ฉันไม่รู้ว่านี่เป็นเรื่องจริงหรือไม่ แต่ฉันต้องการทราบว่าเมื่อฉันเปิดเทอร์มินัลใหม่ (บน osx โดยใช้การตั้งค่าเริ่มต้น) ฉันจะได้รับเชลล์ล็อกอินแม้ว่าฉันจะไม่พิมพ์ชื่อผู้ใช้หรือรหัสผ่านก็ตาม
Kevin Wheeler

4
@KevinWheeler บน OSX โดยค่าเริ่มต้นแอปพลิเคชัน Terminal จะเรียกใช้เปลือกเข้าสู่ระบบ (ดังที่ฉันอธิบายโปรแกรมที่เริ่มเชลล์ตัดสินใจว่าเชลล์ทำหน้าที่เป็นเชลล์ล็อกอินหรือไม่) นั่นไม่ใช่วิธีปกติในการทำสิ่งต่างๆ
Gilles

2
@IAmJulianAcosta ถ้าFOOเป็นตัวแปรสภาพแวดล้อม (เช่น.profileมีexport FOO=something) foo.shแล้วก็สามารถใช้ได้กับกระบวนการย่อยทั้งหมดรวมทั้ง ถ้าคุณเปลี่ยน.profileไปexport FOO=something_elseแล้ว./foo.shจะยังคงพิมพ์somethingครั้งต่อไปที่คุณเข้าสู่ระบบ.
กิลส์

48

หากต้องการทราบว่าคุณอยู่ในเชลล์ล็อกอินหรือไม่:

prompt> echo $0
-bash # "-" is the first character. Therefore, this is a login shell.

prompt> echo $0
bash # "-" is NOT the first character. This is NOT a login shell.

ใน Bash คุณสามารถใช้shopt login_shell:

prompt> shopt login_shell
login_shell     off

(หรือonในล็อกอินเชลล์)

ข้อมูลสามารถพบได้ในman bash(ค้นหาคำขอร้อง) นี่คือข้อความที่ตัดตอนมา:

เปลือกเข้าสู่ระบบเป็นหนึ่งที่มีอักขระตัวแรกของศูนย์อาร์กิวเมนต์เป็น - หรือหนึ่งเริ่มต้นด้วยตัวเลือก --login

คุณสามารถทดสอบได้ด้วยตัวเอง เมื่อใดก็ตามที่คุณ SSH คุณกำลังใช้เชลล์ล็อกอิน ตัวอย่างเช่น:

prompt> ssh user@localhost
user@localhost's password:
prompt> echo $0
-bash

ความสำคัญของการใช้เปลือกเข้าสู่ระบบคือการตั้งค่าใด ๆ ที่/home/user/.bash_profileจะถูกดำเนินการ นี่คือข้อมูลเพิ่มเติมเล็กน้อยหากคุณสนใจ (จากman bash)

"เมื่อ bash ถูกเรียกใช้เป็นเชลล์ล็อกอินแบบโต้ตอบหรือเป็นเชลล์ที่ไม่มีการโต้ตอบกับตัวเลือก --login มันจะอ่านและเรียกใช้คำสั่งจากไฟล์ / etc / profile ก่อนหากไฟล์นั้นอยู่หลังจากอ่านไฟล์นั้นแล้ว มองหา~/.bash_profile, ~/.bash_loginและ~/.profileในลำดับที่และอ่านและรันคำสั่งจากคนแรกที่มีอยู่และสามารถอ่านได้. ตัวเลือก --noprofile อาจจะใช้เมื่อเปลือกจะเริ่มต้นในการยับยั้งการทำงานนี้."


23

ในเปลือกเข้าสู่ระบบ, argv[0][0] == '-'. นี่คือวิธีที่มันรู้ว่ามันเป็นเปลือกเข้าสู่ระบบ

และในบางสถานการณ์มันจะทำงานแตกต่างกันไปขึ้นอยู่กับสถานะ "ล็อกอินเชลล์" เช่นเชลล์ที่ไม่ใช่เชลล์ล็อกอินจะไม่เรียกใช้คำสั่ง "logout"


4
ตามที่man bashมีการเน้นเพิ่ม"เปลือกเข้าสู่ระบบเป็นหนึ่งที่มีอักขระตัวแรกของศูนย์อาร์กิวเมนต์เป็น - หรือหนึ่งเริ่มต้นด้วยตัวเลือก --login "
Wildcard

18

เชลล์เริ่มต้นในเทอร์มินัลใหม่ใน GUI จะเป็นเชลล์แบบไม่ล็อกอิน มันจะมา. bashrc ของคุณ แต่ไม่ใช่. profile ของคุณ


4

ฉันจะอธิบายอย่างละเอียดเกี่ยวกับคำตอบที่ยอดเยี่ยมของ Gilles รวมกับวิธีการของ Timothy สำหรับการตรวจสอบประเภทเชลล์ล็อกอิน

หากคุณต้องการที่จะเห็นสิ่งต่าง ๆ สำหรับตัวคุณเองลองเกร็ดเล็กเกร็ดน้อยและสถานการณ์สมมติ

ตรวจสอบว่าเชลล์เป็นแบบโต้ตอบ (ไม่ใช่ -) หรือไม่

if tty -s; then echo 'This is interactive shell.'; else echo 'This is non-interactive shell.'; fi

ตรวจสอบว่าเชลล์คือการล็อกอิน (ไม่ใช่ -) หรือไม่

หากการส่งออกของecho $0เริ่มต้นด้วย-ก็เข้าสู่ระบบเปลือก ( echo $0ตัวอย่างเช่นการส่งออก: -bash) มิฉะนั้นมันไม่ใช่การเข้าสู่ระบบเปลือก ( echo $0ตัวอย่างเช่นการส่งออก: bash)

if echo $0 | grep -e ^\- 2>&1>/dev/null; then echo "This is login shell."; else echo "This is non-login shell."; fi;

ลองรวบรวมทั้งสองอย่างเข้าด้วยกันเพื่อรับข้อมูลทั้งสองชิ้นพร้อมกัน

THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; 
THIS_SHELL_LOGIN_TYPE='non-login'; 
if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; 
if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"

สถานการณ์:

เซสชัน SSH ทั่วไปโดยไม่มีตัวเลือกพิเศษ

ssh ubuntu@34.247.105.87
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)

ubuntu@ip-172-31-0-70:~$ THIS_SHELL_INTERACTIVE_TYPE='non-interactive';
ubuntu@ip-172-31-0-70:~$ THIS_SHELL_LOGIN_TYPE='non-login';
ubuntu@ip-172-31-0-70:~$ if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi;
ubuntu@ip-172-31-0-70:~$ if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi;
ubuntu@ip-172-31-0-70:~$ echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"

interactive/login

เรียกใช้สคริปต์หรือดำเนินการอย่างชัดเจนผ่านเชลล์ใหม่

ubuntu@ip-172-31-0-70:~$  bash -c 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; 
echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

interactive/non-login

เรียกใช้สคริปต์ท้องถิ่นจากระยะไกล

ssh ubuntu@34.247.105.87 < checkmy.sh
Pseudo-terminal will not be allocated because stdin is not a terminal.
Welcome to Ubuntu 16.04.5 LTS (GNU/Linux 4.4.0-1083-aws x86_64)

non-interactive/login

เรียกใช้คำสั่งผ่าน ssh จากระยะไกล

ssh ubuntu@34.247.105.87 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

non-interactive/non-login

รันคำสั่งผ่าน ssh จากระยะไกลด้วย-tสวิตช์

คุณสามารถร้องขอเชลล์แบบโต้ตอบได้อย่างชัดเจนเมื่อคุณต้องการเรียกใช้คำสั่งจากระยะไกลผ่าน ssh โดยใช้-tสวิตช์

ssh ubuntu@34.247.105.87 -t 'THIS_SHELL_INTERACTIVE_TYPE='non-interactive'; THIS_SHELL_LOGIN_TYPE='non-login'; if tty -s; then THIS_SHELL_INTERACTIVE_TYPE='interactive'; fi; if echo $0 | grep -e ^\- 2>&1>/dev/null; then THIS_SHELL_LOGIN_TYPE='login'; fi; echo "$THIS_SHELL_INTERACTIVE_TYPE/$THIS_SHELL_LOGIN_TYPE"'

interactive/non-login

หมายเหตุ: ในหัวข้อทำไมคำสั่งการทำงานจากระยะไกลไม่ได้login shellข้อมูลเพิ่มเติมที่นี่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.