วิธีการตรวจสอบเปลือกปัจจุบันฉันกำลังทำงาน


633

ฉันจะกำหนดเชลล์ปัจจุบันที่ฉันกำลังใช้งานได้อย่างไร

ผลลัพธ์ของpsคำสั่งเพียงอย่างเดียวจะเพียงพอหรือไม่

สิ่งนี้สามารถทำได้ใน Unix รสชาติที่แตกต่างกันอย่างไร


9
การทดสอบความสามารถเฉพาะ (เช่นการ!ทดแทนหรือไม่) น่าจะพกพาได้มากกว่าการค้นหาชื่อของเชลล์ ประเพณีท้องถิ่นอาจจะมีบางสิ่งบางอย่างที่คุณเรียกใช้ชื่อ/bin/shซึ่งอันที่จริงอาจเป็นเถ้าประทุบตี ฯลฯ
ขยะ

1
@msw: ดูเหมือนความคิดเห็นที่ดียกเว้นมันทำให้ฉันสงสัยว่า "ได้อย่างไร"
ดี

ดูเหมือนว่าไม่มีคำตอบง่ายๆสำหรับคำถามนี้ หากเราไม่สามารถสืบค้นเชลล์ได้บางทีวิธีที่ดีกว่าคือการระบุเชลล์เสมอ ฉันไม่แน่ใจว่ามันเป็นไปได้เสมอ แต่บางทีมันอาจจะสำเร็จได้ง่ายกว่าที่คนทั่วไปคิดเอาไว้
ดี

สิ่งนี้อาจช่วยได้ -> opensourceforgeeks.blogspot.in/2013/05/…
Aniket Thakur

@Aniket ไม่ได้ช่วยอะไรมากเท่าที่คุณคิดนั่นเป็นเพียงความสนใจในกระบวนการเชลล์เชิงโต้ตอบเท่านั้น
Toby Speight

คำตอบ:


793
  • มีสามวิธีในการค้นหาชื่อของไฟล์สั่งการของเชลล์ปัจจุบัน:

    โปรดทราบว่าวิธีการทั้งสามนี้อาจถูกหลอกได้หากมีการเรียกใช้งานเชลล์ได้/bin/shแต่เป็นชื่อที่เปลี่ยนไปจริง ๆbash(ซึ่งเกิดขึ้นบ่อยครั้ง)

    ดังนั้นคำถามที่สองของคุณว่าการpsตอบสนองจะทำอย่างไรกับ " ไม่เสมอไป "

    1. echo $0 - จะพิมพ์ชื่อโปรแกรม ... ซึ่งในกรณีของเชลล์คือเชลล์จริง

    2. ps -ef | grep $$ | grep -v grep- สิ่งนี้จะค้นหา ID กระบวนการปัจจุบันในรายการกระบวนการที่กำลังทำงาน เนื่องจากกระบวนการปัจจุบันคือเชลล์จึงจะรวมอยู่

      สิ่งนี้ไม่น่าเชื่อถือ 100% เนื่องจากคุณอาจมีกระบวนการอื่น ๆที่psรายการมีหมายเลขเดียวกันกับ ID กระบวนการของเชลล์โดยเฉพาะถ้า ID นั้นมีจำนวนน้อย (ตัวอย่างเช่นหาก PID ของเชลล์คือ "5" คุณอาจพบกระบวนการที่เรียกว่า "java5" หรือ "perl5" ในgrepเอาต์พุตเดียวกัน!) นี่เป็นปัญหาที่สองด้วยวิธีการ "ps" ที่ด้านบนของความไม่สามารถพึ่งพาชื่อเชลล์

    3. echo $SHELL- เส้นทางไปยังเชลล์ปัจจุบันจะถูกเก็บไว้เป็นSHELLตัวแปรสำหรับเชลล์ใด ๆ ข้อแม้สำหรับอันนี้คือถ้าคุณเรียกใช้เชลล์อย่างชัดเจนว่าเป็น subprocess (ตัวอย่างเช่นไม่ใช่เชลล์ล็อกอินของคุณ) คุณจะได้รับค่าเชลล์ล็อกอินของคุณแทน หากเป็นไปได้ให้ใช้วิธีการpsหรือ$0


  • อย่างไรก็ตามหากปฏิบัติการไม่ตรงกับเปลือกจริงของคุณ (เช่น/bin/shจริง ๆ แล้วทุบตีหรือ ksh) คุณต้องมีการวิเคราะห์พฤติกรรม นี่คือตัวแปรสภาพแวดล้อมบางตัวสำหรับเชลล์ต่างๆ:

    • $version ตั้งอยู่บน tcsh

    • $BASH ตั้งอยู่บนทุบตี

    • $shell (ตัวพิมพ์เล็ก) ถูกตั้งค่าเป็นชื่อเชลล์จริงใน csh หรือ tcsh

    • $ZSH_NAME ตั้งอยู่บน zsh

    • ksh มี$PS3และ$PS4ตั้งค่าในขณะที่เชลล์เป้าหมายปกติ ( sh) มี$PS1และ$PS2ตั้งค่าเท่านั้น ซึ่งมักจะดูเหมือนยากที่จะแยกแยะความแตกต่าง - The เพียงความแตกต่างในการตั้งค่าทั้งหมดของตัวแปรสภาพแวดล้อมระหว่างshและkshเราได้ติดตั้งบน Solaris boxen คือ$ERRNO, $FCEDIT, $LINENO, $PPID, $PS3, $PS4, $RANDOM, และ$SECONDS$TMOUT


$ {. sh.version} ตั้งไว้ที่ ksh93
fpmurphy

14
ps -p $$เป็นแมทธิว Slatteryชี้ให้เห็น สำหรับksh: หรือecho $KSH_VERSION echo ${.sh.version}
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

@Dennish - ksh ของฉันในขณะนี้ยังไม่มีชุด KSH_VERSION และecho ${.sh.version}ส่งคืน "การทดแทนไม่ดี" ดูโซลูชันของฉันด้านบน
DVK

3
ps -ef | grep …... นี่คือไม่ 100% ที่เชื่อถือได้เป็น ...” การใช้การแสดงออกปกติโดยง่ายผ่านทางegrepหรือgrep -eสามารถนำความน่าเชื่อถือขึ้นไปสำหรับทุกเจตนาและวัตถุประสงค์ ps -ef | egrep "^\s*\d+\s+$$\s+"100%: สิ่งที่^ทำให้แน่ใจว่าเราเริ่มต้นจากจุดเริ่มต้นของบรรทัด\d+กิน UID ขึ้น$$ตรงกับ PID และ\s*และ\s+บัญชีสำหรับ & ตรวจสอบช่องว่างระหว่างส่วนอื่น ๆ
Slipp D. Thompson

2
@ SlippD.Thompson ไม่ทำงานใน GNU / Linux แต่สิ่งนี้ดูเหมือนจะใช้ได้:ps -ef | awk '$2==pid' pid=$$
jarno

98

ps -p $$

ควรทำงานได้ทุกที่ที่โซลูชั่นที่เกี่ยวข้องps -efและgrepทำ (ในตัวแปร Unix ใด ๆ ที่สนับสนุนตัวเลือก POSIX สำหรับps ) และจะไม่ได้รับผลกระทบจากผลบวกปลอมที่เกิดขึ้นจากการ grepping สำหรับลำดับตัวเลขซึ่งอาจปรากฏที่อื่น


12
เปลือกบางมีรุ่นในตัวของตัวเองpsซึ่งอาจจะไม่เข้าใจดังนั้นคุณอาจจำเป็นต้องใช้-p /bin/ps -p $$
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

13
ทั้งหมดหอยฉันคุ้นเคยกับเข้าใจ$$ยกเว้นที่คุณจะต้องใช้fish ps -p %self
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

3
/bin/psที่จริงแล้วคุณไม่ควรพึ่งพาเส้นทางแข็งเช่น psได้อย่างง่ายดาย (ที่จริงมันเป็นเรื่องปกติมากในปัจจุบัน) /usr/binได้รับการติดตั้งใน $(which ps) -p $$เป็นวิธีที่ดีกว่า แน่นอนว่าสิ่งนี้จะไม่ทำงานในปลาและอาจเป็นเปลือกหอยอื่น ๆ ฉันคิดว่ามันอยู่(which ps) -p %selfในปลา
Aron Cederholm

1
ในบางระบบที่น้อยที่สุดเช่นคอนเทนเนอร์ docker-slim docker, ps อาจไม่มีอยู่ ในกรณีนี้วิธีการนี้ยังใช้งานได้:readlink /proc/$$/exe
mxmlnkn

หากคุณshถูกจำลองโดยbashps-p ให้คุณ/usr/bin/bashแม้คุณจะเรียกใช้เป็นsh
Ding-Yi Chen

45

ลอง

ps -p $$ -oargs=

หรือ

ps -p $$ -ocomm=

4
อันนี้สั้นดีนะ ps -o fname --no-headers $$ผมใช้ตัวเอง
Anne van Rossum

ขอบคุณ test `ps -p $$ -ocomm=` == "bash" && do_something_that_only_works_in_bashฉันพบนี้เป็นตัวเลือกที่ดีที่สุดในการใช้งานในสคริปต์คำสั่งเฉพาะยามทุบตี (บรรทัดถัดไปในสคริปต์ของฉันมีค่าเทียบเท่ากับ csh.)
craq

1
ฉันพบว่าหากคุณทำสิ่งนี้จากภายใน subshell มันสามารถนำไปสู่การเพิ่มเสแสร้งบรรทัดโดยการจับคู่ PID ของผู้ปกครองเช่นเดียวกับกระบวนการเปลือกจริง สำหรับสิ่งนี้ฉันใช้-qแทน-p:SHELL=$(ps -ocomm= -q $$)
Steve

35

หากคุณเพียงต้องการให้แน่ใจว่าผู้ใช้กำลังเรียกใช้สคริปต์ด้วย Bash:

if [ ! -n "$BASH" ] ;then echo Please run this script $0 with bash; exit 1; fi

1
ควรจะอยู่ใกล้กับด้านบนสุด ขอบคุณมาก.
Alex Skrypnyk

4
ไม่ควรอยู่ใกล้กับด้านบนเพราะไม่สามารถตอบคำถามได้เลย หากคำถามจะเป็น "วิธีตรวจสอบว่าสคริปต์ทำงานภายใต้การทุบตี" ฉันลงคะแนนให้หรือไม่
David Ferenczy Rogožan

2
@DawidFerenczy - คำถามนี้เป็นผลลัพธ์อันดับต้นเมื่อคุณค้นหาวลีนั้น ในระยะยาวฉันคิดว่ามันสำคัญมากที่คำตอบจะตอบสิ่งที่ผู้คนกำลังมองหาแทนที่จะตอบคำถามที่เป็นต้นฉบับ
ArtOfWarfare

3
นอกจากนี้ตัวแปร $ BASH จะถูกกำหนดภายใต้ tcsh หากมีการเรียกใช้ tcsh จาก bash
18446744073709551615

มันมีประโยชน์มากขอบคุณ เพิ่งปรับให้เข้ากันแล้วใส่นี่เป็นบรรทัดที่สองหลังจาก#!/bin/bash: if [ ! -n "$BASH" ] ;then exec bash $0; fi. ด้วยบรรทัดนี้สคริปต์จะรันโดยใช้ bash แม้ว่าจะเริ่มใช้ ksh หรือ sh กรณีใช้งานของฉันไม่ต้องการอาร์กิวเมนต์บรรทัดคำสั่ง แต่สามารถเพิ่มได้$0หากจำเป็น
joanis

20

คุณสามารถลอง:

ps | grep `echo $$` | awk '{ print $4 }'

หรือ:

echo $SHELL

6
grep ตามด้วย awk คือ/pattern/ { action }อะไรจะทำเมื่อใด
Jens

# in zshell alias shell = 'echo $ {SHELL: t}'
SergioAraujo

4
$SHELLตัวแปรสภาพแวดล้อมมีเชลล์ซึ่งกำหนดค่าเป็นค่าเริ่มต้นสำหรับผู้ใช้ปัจจุบัน มันไม่ได้สะท้อนถึงเชลล์ซึ่งทำงานอยู่ในขณะนี้ นอกจากนี้ยังใช้งานได้ps -p $$ดีกว่าการ grepping $$ เนื่องจากมีผลบวกปลอม
David Ferenczy Rogožan

$ SHELL env ตัวแปรชี้ไปที่เชลล์ 'parent' ตามที่ระบุในข้อมูลจำเพาะ POSIX: SHELLตัวแปรนี้จะแสดงชื่อพา ธ ของล่ามภาษาคำสั่งที่ผู้ใช้ต้องการ ดังนั้นมูลค่าของ $ SHELL อาจไม่ใช่เชลล์ปัจจุบัน
Theo

ทั้งหมดภายในawk,ps | awk '$1=='$$' { n=split($4,a,"/"); print a[n] }'
go2null

16

$SHELLไม่จำเป็นต้องแสดงเชลล์ปัจจุบันเสมอไป มันสะท้อนให้เห็นถึงเปลือกเริ่มต้นที่จะเรียกเท่านั้น

ในการทดสอบข้างต้นกล่าวbashคือเปลือกเริ่มต้นลองecho $SHELLและจากนั้นในขั้วเดียวกันได้รับในบางเปลือกอื่น ๆ ( KornShell (ksh) ตัวอย่าง) $SHELLและลอง คุณจะเห็นผลลัพธ์เป็น bash ในทั้งสองกรณี

cat /proc/$$/cmdlineที่จะได้รับชื่อของเปลือกปัจจุบันใช้ readlink /proc/$$/exeและเส้นทางที่จะปฏิบัติการโดยเปลือก


8
... /procให้คุณมี
tripleee

10

psเป็นวิธีที่เชื่อถือได้มากที่สุด ตัวแปรสภาพแวดล้อม SHELL ไม่รับประกันว่าจะถูกตั้งค่าและแม้ว่าจะเป็นมันก็สามารถปลอมแปลงได้อย่างง่ายดาย


12
+1 $ SHELL เป็นเชลล์เริ่มต้นสำหรับโปรแกรมที่จำเป็นต้องวางไข่ ไม่จำเป็นต้องสะท้อนถึงเชลล์ที่ใช้งานอยู่ในปัจจุบัน
Jim Lewis

8

ฉันมีเคล็ดลับง่าย ๆ เพื่อค้นหาเชลล์ปัจจุบัน เพียงพิมพ์สตริงแบบสุ่ม (ซึ่งไม่ใช่คำสั่ง) มันจะล้มเหลวและส่งคืนข้อผิดพลาด "ไม่พบ" แต่เมื่อเริ่มต้นบรรทัดมันจะพูดว่าเชลล์ตัวใดเป็น:

ksh: aaaaa: not found [No such file or directory]
bash: aaaaa: command not found

3
ไม่มีสคริปต์ที่ดี echo 'aaaa' > script; chmod +x script; ./scriptให้./script.sh: 1: aaaa: not found
ผอม

6

ต่อไปนี้จะให้เชลล์จริงที่ใช้เสมอ - จะได้รับชื่อของไฟล์เรียกทำงานจริงและไม่ใช่ชื่อเชลล์ (เช่นksh93แทนkshฯลฯ ) สำหรับก็จะแสดงเปลือกที่ใช้จริงคือ/bin/shdash

ls -l /proc/$$/exe | sed 's%.*/%%'

ฉันรู้ว่ามีหลายคนที่บอกว่าlsเอาต์พุตไม่ควรถูกประมวลผล แต่ความน่าจะเป็นที่คุณจะมีเชลล์ที่คุณใช้นั้นถูกตั้งชื่อด้วยอักขระพิเศษหรือวางไว้ในไดเรกทอรีที่มีอักขระพิเศษคืออะไร หากยังคงเป็นเช่นนั้นมีตัวอย่างอื่น ๆ อีกมากมายที่ทำให้แตกต่าง

ดังที่Toby Speightชี้ให้เห็นว่านี่จะเป็นวิธีที่เหมาะสมและสะอาดกว่าในการบรรลุเป้าหมายเดียวกัน:

basename $(readlink /proc/$$/exe)

3
เพียงแค่นี้ก็ผิดพลาดใน Unices /procทั้งหมดที่ไม่ได้ให้ ไม่ใช่กล่องลินุกซ์ทั้งหมดของโลก
Jens

5
และถ้าคุณอยู่บน Linux เราต้องการbasename $(readlink /proc/$$/exe)ที่จะls+ +sed echo
Toby Speight

1
นี้จะให้ชื่อของจริงปฏิบัติการไม่ได้เกิดขึ้นจริงเปลือก เมื่อเชลล์จริงถูกลิงก์เป็นแอปเพล็ต busybox ให้บอกว่าash -> /bin/busyboxสิ่งนี้จะให้ / bin / busybox
stepse

6

ฉันได้ลองวิธีการต่าง ๆ มากมายและวิธีที่ดีที่สุดสำหรับฉันคือ:

ps -p $$

นอกจากนี้ยังทำงานภายใต้Cygwinและไม่สามารถสร้างผลบวกปลอมเป็น PID grepping ด้วยการทำความสะอาดบางอย่างมันจะแสดงผลเฉพาะชื่อที่ปฏิบัติการได้ (ภายใต้ Cygwin พร้อมพา ธ ):

ps -p $$ | tail -1 | awk '{print $NF}'

คุณสามารถสร้างฟังก์ชั่นเพื่อไม่ต้องจำ:

# Print currently active shell
shell () {
  ps -p $$ | tail -1 | awk '{print $NF}'
}

... shellและแล้วก็ดำเนินการ

มันได้รับการทดสอบภายใต้ Debian และ Cygwin


จากการตั้งค่าของฉัน (Cygwin | Windows 7) คำตอบของคุณคือคำตอบที่ดีที่สุดและ ps -p $$ | หาง -1 | gawk '{print $ NF}' ทำงานได้แม้จาก cmd โดยไม่ต้อง $ bash โปรดสังเกตว่าเพ่งพิศแทนที่จะเป็น awk เนื่องจาก awk ใช้งานได้จากการทุบตีเท่านั้น
WebComer

@WebComer ขออภัยฉันไม่แน่ใจว่าสิ่งที่คุณหมายถึงโดย " ทำงานได้จาก cmd โดยไม่ต้อง $ bash " แม้ว่าคุณจะมีพอร์ตของ Windows ps, tailและgawk, cmd ไม่ได้กำหนด$$เป็นมัน PID ดังนั้นแน่นอนไม่สามารถทำงานภายใต้คำสั่งธรรมดา
David Ferenczy Rogožan

ทำไมไม่ง่าย ๆps -p$$ -o comm=? POSIX กล่าวว่าการระบุส่วนหัวที่ว่างทั้งหมดจะไม่แสดงส่วนหัวอย่างสมบูรณ์ เรายังคงล้มเหลว (เช่นpsคำตอบทั้งหมด) เมื่อเราได้รับสคริปต์ที่ดำเนินการโดยตรง (เช่น#!/bin/sh)
Toby Speight

5

ตัวแปรของฉันเกี่ยวกับการพิมพ์กระบวนการผู้ปกครอง:

ps -p $$ | awk '$1 == PP {print $4}' PP=$$

อย่าเรียกใช้แอปพลิเคชันที่ไม่จำเป็นเมื่อ AWK ทำเพื่อคุณ


2
ทำไมถึงเรียกใช้สิ่งที่ไม่จำเป็นawkเมื่อไหร่ที่ps -p "$$" -o 'comm='สามารถทำเพื่อคุณ?
Toby Speight

5

มีหลายวิธีในการค้นหาเชลล์และเวอร์ชันที่สอดคล้องกัน ที่นี่มีน้อยที่เหมาะกับฉัน

ซื่อตรง

  1. $> echo $ 0 (ให้ชื่อโปรแกรมแก่คุณในกรณีของฉันเอาต์พุตคือ-bash )
  2. $> $ SHELL (สิ่งนี้จะนำคุณเข้าสู่เชลล์และในทันทีคุณจะได้รับชื่อเชลล์และเวอร์ชันในกรณีของฉันbash3.2 $ .)
  3. $> echo $ SHELL (สิ่งนี้จะให้พา ธ ที่ใช้งานได้ในกรณีของฉัน/ bin / bash )
  4. $> $ SHELL - รุ่น (จะให้ข้อมูลที่สมบูรณ์เกี่ยวกับซอฟต์แวร์เชลล์พร้อมประเภทใบอนุญาต)

วิธีการแฮ็ก

$> ******* (พิมพ์ชุดอักขระสุ่มและในผลลัพธ์คุณจะได้รับชื่อเชลล์ในกรณีของฉัน-bash: ตอนที่ 2-a-sample-isomorphic-app: ไม่พบคำสั่ง )


3

โดยมีเงื่อนไขว่า/bin/shสนับสนุนมาตรฐาน POSIX และระบบของคุณมีlsofคำสั่งติดตั้งซึ่งเป็นทางเลือกที่เป็นไปlsofได้ในกรณีนี้pid2pathคุณยังสามารถใช้ (หรือปรับ) สคริปต์ต่อไปนี้ที่พิมพ์เส้นทางแบบเต็ม:

#!/bin/sh
# cat /usr/local/bin/cursh
set -eu
pid="$$"

set -- sh bash zsh ksh ash dash csh tcsh pdksh mksh fish psh rc scsh bournesh wish Wish login

unset echo env sed ps lsof awk getconf

# getconf _POSIX_VERSION  # reliable test for availability of POSIX system?
PATH="`PATH=/usr/bin:/bin:/usr/sbin:/sbin getconf PATH`"
[ $? -ne 0 ] && { echo "'getconf PATH' failed"; exit 1; }
export PATH

cmd="lsof"
env -i PATH="${PATH}" type "$cmd" 1>/dev/null 2>&1 || { echo "$cmd not found"; exit 1; }

awkstr="`echo "$@" | sed 's/\([^ ]\{1,\}\)/|\/\1/g; s/ /$/g' | sed 's/^|//; s/$/$/'`"

ppid="`env -i PATH="${PATH}" ps -p $pid -o ppid=`"
[ "${ppid}"X = ""X ] && { echo "no ppid found"; exit 1; }

lsofstr="`lsof -p $ppid`" || 
   { printf "%s\n" "lsof failed" "try: sudo lsof -p \`ps -p \$\$ -o ppid=\`"; exit 1; }

printf "%s\n" "${lsofstr}" | 
   LC_ALL=C awk -v var="${awkstr}" '$NF ~ var {print $NF}'

1
งานนี้ในปลา! แต่สำหรับฉันล้มเหลวในการทุบตีเนื่องจากตัวเลือก-i(-> ละเว้นสภาพแวดล้อม) ไปenvยังบรรทัดที่คุณตรวจสอบlsofว่ามีอยู่ มันล้มเหลวด้วย: env -i PATH="${PATH}" type lsof->env: ‘type’: No such file or directory
hoijui

2

หากคุณเพียงต้องการตรวจสอบว่าคุณกำลังใช้งาน (รุ่นที่เฉพาะเจาะจง) Bash วิธีที่ดีที่สุดในการทำเช่นนั้นคือการใช้$BASH_VERSINFOตัวแปรอาร์เรย์ ในฐานะที่เป็นตัวแปรอาเรย์ (อ่านอย่างเดียว) จะไม่สามารถตั้งค่าในสภาพแวดล้อมดังนั้นคุณสามารถมั่นใจได้ว่ามันจะมา (ถ้าทั้งหมด) จากเปลือกปัจจุบัน

อย่างไรก็ตามตั้งแต่ทุบตีมีพฤติกรรมที่แตกต่างกันเมื่อเรียกว่าเป็นshคุณยังต้องตรวจสอบตัวแปรสภาพแวดล้อมที่มีปลาย$BASH/bash

ในสคริปต์ฉันเขียนที่ใช้ชื่อฟังก์ชั่นด้วย-(ไม่ขีดเส้นใต้) และขึ้นอยู่กับการเชื่อมโยงอาร์เรย์ (เพิ่มใน Bash 4) ฉันมีการตรวจสอบสติต่อไปนี้ (พร้อมข้อความแสดงข้อผิดพลาดของผู้ใช้ที่เป็นประโยชน์):

case `eval 'echo $BASH@${BASH_VERSINFO[0]}' 2>/dev/null` in
    */bash@[456789])
        # Claims bash version 4+, check for func-names and associative arrays
        if ! eval "declare -A _ARRAY && func-name() { :; }" 2>/dev/null; then
            echo >&2 "bash $BASH_VERSION is not supported (not really bash?)"
            exit 1
        fi
        ;;
    */bash@[123])
        echo >&2 "bash $BASH_VERSION is not supported (version 4+ required)"
        exit 1
        ;;
    *)
        echo >&2 "This script requires BASH (version 4+) - not regular sh"
        echo >&2 "Re-run as \"bash $CMD\" for proper operation"
        exit 1
        ;;
esac

คุณสามารถละเว้นการตรวจสอบการทำงานของฟังก์ชั่นหวาดระแวงสำหรับคุณสมบัติในกรณีแรกและเพียงสมมติว่าเวอร์ชั่น Bash ในอนาคตจะเข้ากันได้


2

ไม่มีคำตอบใดที่ใช้งานได้กับfishเชลล์ (ไม่มีตัวแปร$$หรือ$0)

งานนี้สำหรับฉัน (ทดสอบบนsh, bash, fish, ksh, csh, true, tcshและzsh; openSUSE 13.2):

ps | tail -n 4 | sed -E '2,$d;s/.* (.*)/\1/'

bashคำสั่งนี้ออกผลลัพธ์สตริงเหมือน ที่นี่ฉันใช้psแต่tailและsed(ไม่มีส่วนขยายของ GNU ให้ลองเพิ่ม--posixเพื่อตรวจสอบ) มันเป็นคำสั่ง POSIX มาตรฐานทั้งหมด ฉันแน่ใจว่าtailสามารถลบออกได้ แต่ฉันsedไม่แข็งแรงพอที่จะทำสิ่งนี้

ดูเหมือนว่าฉันว่าโซลูชันนี้ไม่สามารถพกพาได้มากเนื่องจากไม่สามารถทำงานบน OS X ได้ :(


ฉันsed: invalid option -- 'E'ใช้ bash 3.2.51 และ tcsh 6.15.00
craq

2

ทางออกของฉัน:

ps -o command | grep -v -e "\<ps\>" -e grep -e tail | tail -1

สิ่งนี้ควรพกพาข้ามแพลตฟอร์มและเชลล์ต่างๆ มันใช้psเหมือนโซลูชันอื่น ๆ แต่ไม่พึ่งพาsedหรือawkกรองขยะจากท่อและpsตัวมันเองเพื่อให้เชลล์ควรเป็นรายการสุดท้าย วิธีนี้เราไม่จำเป็นต้องพึ่งพาตัวแปร PID ที่ไม่ได้พกพาหรือเลือกจากเส้นและคอลัมน์ที่เหมาะสม

ฉันได้ทดสอบกับ Debian และ macOS ด้วย Bash, Z shell ( zsh) และfish (ซึ่งใช้ไม่ได้กับโซลูชันส่วนใหญ่โดยไม่เปลี่ยนนิพจน์สำหรับปลาโดยเฉพาะเพราะใช้ตัวแปร PID ที่แตกต่างกัน)


1
echo $$ # Gives the Parent Process ID 
ps -ef | grep $$ | awk '{print $8}' # Use the PID to see what the process is.

จากคุณจะรู้ว่าสิ่งที่เปลือกปัจจุบันของคุณคืออะไร? .


3
ไม่ใช่กระบวนการหลัก - เป็นกระบวนการปัจจุบัน
หยุดชั่วคราวจนกว่าจะมีการแจ้งให้ทราบต่อไป

7
การใช้grep $$ไม่น่าเชื่อถือ ps -ef | awk -v pid=$$ '$2==pid { print $8 }'จะดีกว่า แต่ทำไมไม่ใช้เพียงps -p $$?
musiphil

1

บน Mac OS X (และ FreeBSD):

ps -p $$ -axco command | sed -n '$p' 

2
พยายามนี้ในขณะที่ใช้และมันทำให้ผมzsh -bash
user137369

ในระบบของฉัน (ตอนนี้) ทดสอบด้วย bash และ dash ผลตอบแทนนี้mutt... : -b
F. Hauri

1

ไม่จำเป็นต้องใส่ Greid PID จากเอาต์พุตของ "ps" เนื่องจากคุณสามารถอ่านบรรทัดคำสั่งที่เกี่ยวข้องสำหรับ PID ใด ๆ จากโครงสร้างไดเร็กทอรี / proc:

echo $(cat /proc/$$/cmdline)

อย่างไรก็ตามนั่นอาจจะไม่ดีไปกว่าเพียงแค่:

echo $0

เกี่ยวกับการใช้งานเชลล์ที่แตกต่างจากชื่อจริง ๆ แนวคิดหนึ่งคือขอรุ่นจากเชลล์โดยใช้ชื่อที่คุณได้รับก่อนหน้านี้:

<some_shell> --version

sh ดูเหมือนจะล้มเหลวด้วยรหัสออก 2 ในขณะที่คนอื่นให้สิ่งที่มีประโยชน์ (แต่ฉันไม่สามารถยืนยันได้ทั้งหมดเนื่องจากฉันไม่มี)

$ sh --version
sh: 0: Illegal option --
echo $?
2

1

นี่ไม่ใช่วิธีที่สะอาดมาก แต่ทำในสิ่งที่คุณต้องการ

# MUST BE SOURCED..
getshell() {
    local shell="`ps -p $$ | tail -1 | awk '{print $4}'`"

    shells_array=(
    # It is important that the shells are listed in descending order of their name length.
        pdksh
        bash dash mksh
        zsh ksh
        sh
    )

    local suited=false
    for i in ${shells_array[*]}; do
        if ! [ -z `printf $shell | grep $i` ] && ! $suited; then
            shell=$i
            suited=true
        fi
    done

    echo $shell
}
getshell

$(getshell) --versionตอนนี้คุณสามารถใช้

แม้ว่าจะใช้ได้กับเชลล์ KornShell (ksh) เท่านั้น


1
"ใช้งานได้กับเชลล์แบบ ksh เท่านั้น" คุณกำลังบอกว่าฉันต้องตรวจสอบเชลล์ก่อนใช้งานหรือไม่ อืม ...
jpaugh

@jpaugh รายการจะต้องได้รับการสนับสนุนจากเปลือกจัดหารหัสนี้ซึ่งไม่ได้เป็นกรณีสำหรับdash, yashฯลฯ โดยปกติถ้าคุณกำลังใช้bash, zsh, kshสิ่งที่ - คุณไม่ควรดูแลเกี่ยวกับสิ่งต่างๆ
theoden8

ดังนั้นคุณจะนับทุบตีว่า "เหมือน ksh"? เข้าใจแล้ว นั่นเหมาะสมกว่า
jpaugh

@jpaugh นั่นคือสิ่งที่ฉันหมายถึงเพราะkshชุดของคุณสมบัติส่วนใหญ่เป็นส่วนย่อยของbashคุณสมบัติ (ยังไม่ได้ตรวจสอบอย่างละเอียด)
theoden8

1

ทำสิ่งต่อไปนี้เพื่อทราบว่าเชลล์ของคุณใช้ Dash / Bash หรือไม่

ls –la /bin/sh:

  • ถ้าผลลัพธ์คือ/bin/sh -> /bin/bash==> จากนั้นเชลล์ของคุณกำลังใช้ Bash

  • ถ้าผลลัพธ์คือ/bin/sh ->/bin/dash==> จากนั้นเชลล์ของคุณใช้ Dash

หากคุณต้องการเปลี่ยนจาก Bash เป็น Dash หรือกลับกันใช้รหัสด้านล่าง:

ln -s /bin/bash /bin/sh (เปลี่ยนเชลล์เป็น Bash)

หมายเหตุ : หากคำสั่งดังกล่าวส่งผลให้เกิดข้อผิดพลาดว่า / bin / sh มีอยู่แล้วให้ลบ / bin / sh แล้วลองอีกครั้ง



-1

กรุณาใช้คำสั่งด้านล่าง:

ps -p $$ | tail -1 | awk '{print $4}'

สิ่งแรกคือเรื่องไร้สาระecho $SHELLทำในสิ่งที่คุณพยายามจะทำและทำมันให้ดี อันที่สองยังไม่ดีเนื่องจาก$SHELLตัวแปรสภาพแวดล้อมมีเชลล์เริ่มต้นสำหรับผู้ใช้ปัจจุบันไม่ใช่เชลล์ที่กำลังทำงาน ถ้าผมมีตัวอย่างเช่นbashชุดเปลือกเริ่มต้นดำเนินการzshและมันจะพิมพ์echo $SHELL bash
David Ferenczy Rogožan

คุณถูกต้อง Dawid Ferenczy เราสามารถใช้คำสั่ง ps เพื่อกำหนดเชลล์ปัจจุบัน [# ps -p $$ | หาง -1 | awk '{พิมพ์ $ 4}']
Ranjithkumar T

echo $SHELLอาจเป็นขยะ: ~ $ echo $SHELL /bin/zsh ~ $ bash bash-4.3$ echo $SHELL /bin/zsh bash-4.3$
SaltwaterC

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