Làm thế nào để tôi biết tôi có bao nhiêu vỏ phụ?


40

Đôi khi tôi làm những việc như bắt đầu một shell con từ vim với :sh. Làm thế nào để tôi biết nếu tôi ở trong một lớp vỏ phụ, nơi exitsẽ trả lại cho tôi một cấp độ, so với việc ở trong lớp vỏ ngoài cùng, nơi exitsẽ đăng xuất tôi hoặc đóng phiên của tôi.

Có một số loại vật tổ Inception tôi có thể quay hoặc một cái gì đó để biết tôi sâu bao nhiêu cấp?



1
Chào! Một cách nhanh chóng để xem bạn có ở trong một subshell hay không là echo $0. Nếu đó là vỏ toplevel, nó có thể sẽ bắt đầu bằng dấu gạch ngang. (Điều này đúng với ít nhất là bash và dấu gạch ngang có nghĩa là nó được gọi là shell đăng nhập.)
jpaugh

Câu trả lời:


40

Bạn có thể sử dụng lệnh pstree(đi kèm theo mặc định với Ubuntu). Dưới đây là ví dụ - hiện tại tôi chỉ có một cửa sổ đầu cuối mở trên WSL:

User@Wsl:~$ pstree
init─┬─init───bash───pstree
     └─{init}

User@Wsl:~$ bash
User@Wsl:~$ sh
$ bash
User@Wsl:~$ pstree
init─┬─init───bash───bash───sh───bash───pstree
     └─{init}

Trong môi trường Linux / Ubuntu thực tế, cây quy trình sẽ phức tạp hơn. Chúng ta có thể lọc cây theo tùy chọn -ssẽ hiển thị cha mẹ của một quy trình được chọn. Vì vậy, lệnh của chúng ta có thể là pstree -s $$, nơi $$là một biến môi trường có chứa PID hiện tại:

User@Ubuntu:~$ pstree -s $$
systemd──lightdm──lightdm──upstart──gnome-terminal-──bash──pstree

User@Ubuntu:~$ bash
User@Ubuntu:~$ sh
$ bash
User@Ubuntu:~$ pstree -s $$
systemd──lightdm──lightdm──upstart──gnome-terminal-──bash──bash──sh──bash──pstree

Tài liệu tham khảo:


Thêm chỉ báo vào dấu nhắc của shell: Dựa trên ý tưởng của @ waltinator , để có một bộ đếm ở phía trước dấu nhắc cho một số shell khác nhau khi mức độ sâu hơn một, tôi đã thêm các dòng, được hiển thị bên dưới bản demo, ở dưới cùng của các tệp lệnh run ( ~/.*rc) có liên quan .

Tôi đã thực hiện các thử nghiệm trên WSL, Ubuntu 16.04, Ubuntu 18.04 (máy chủ / máy tính để bàn), Ubuntu 19.04, trong phiên gnome-terminal, tty và ssh. Đây là cách nó hoạt động:

nhập mô tả hình ảnh ở đây

Hạn chế là: bộ đếm chỉ hoạt động ở độ sâu 13-14, tùy thuộc vào HĐH. Tôi không có ý định điều tra lý do :)

  • bash> .bashrc:

    DEPTH=$(($(pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>') - 1))
    if (( DEPTH > 1 )); then PS1=$DEPTH:$PS1; fi
  • cshtcsh> .cshrc:

    @ DEPTH = `pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>'` - 0
    if ( $DEPTH > 1 ) then; set prompt="$DEPTH":"$prompt"; endif
  • zsh> .zshrc:

    DEPTH=$(($(pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>') - 1))
    if (( DEPTH > 1 )); then PROMPT=$DEPTH:$PROMPT; fi
  • ksh> .kshrc:

    DEPTH=$(($(pstree -s $$ | sed -r 's/\-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>') - 0))
    if (( DEPTH > 1 )); then PS1="$DEPTH":"$PS1"'$ '; fi
  • shđó thực sự là dashtrên Ubuntu - ở đây mọi thứ hơi phức tạp và có dây (đọc các tài liệu tham khảo bên dưới để biết thêm thông tin):

    1. Chỉnh sửa ~/.profiletệp và thêm dòng sau ở dưới cùng:

      ENV=$HOME/.shrc; export ENV
    2. Tạo tập tin ~/.shrcvới nội dung sau, lưu ý kshcũng đọc $ENV:

      #!/bin/dash
      DEPTH=$(pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>')
      if [ "$0" != 'ksh' ]; then DEPTH=$((DEPTH - 1)); fi
      if [ "$DEPTH" -gt 1 ]; then export PS1='$DEPTH:\$ '; fi

Tài liệu tham khảo:


Tạo một lệnh sẽ xuất độ sâu: Một tùy chọn khác là tạo lệnh shell sẽ xuất độ sâu. Với mục đích này, hãy tạo tệp thực thi (do đó nó có thể truy cập được trên toàn hệ thống):/usr/local/bin/depth

sudo touch /usr/local/bin/depth
sudo chmod +x /usr/local/bin/depth

Chỉnh sửa tệp với trình chỉnh sửa yêu thích của bạn và thêm các dòng sau vào nội dung của nó:

#!/bin/bash

SHELLS='(bash|zsh|sh|dash|ksh|csh|tcsh)'
DEPTH=$(pstree -s $$ | sed -r 's/-+/\n/g' | grep -Ec "\<$SHELLS\>")

if [[ $@ =~ -v ]]
then
        pstree -s $$ | sed -r 's/-+/\n/g' | grep -E "\<$SHELLS\>" | cat -n
fi

echo "DEPTH: $DEPTH"

[[ $DEPTH -gt 1 ]] && exit 0 || exit 1

Kịch bản trên có hai tùy chọn -vhoặc --verbosesẽ xuất ra một danh sách các shell liên quan. Và tùy chọn khác sẽ kiểm tra xem độ sâu có lớn hơn một hay không và dựa trên điều này sẽ trở lại exit 0hoặc exit 1, vì vậy bạn có thể sử dụng nó theo cách này depth && exit. Dưới đây là một vài ví dụ về cách sử dụng:

User@Ubuntu:~$ depth          # we are at the 1st level - bash
DEPTH: 1
User@Ubuntu:~$ sh           
$ csh                         # we are at the 2nd level - dash
Ubuntu:~% depth               # we are at the 3rd level - csh
DEPTH: 3
Ubuntu:~% ksh
$ depth -v                    # we are at the 4th level - ksh
     1  bash
     2  sh
     3  csh
     4  ksh
DEPTH: 4
$ depth && exit               # exit to the 3rd level - csh
DEPTH: 4
Ubuntu:~% depth && exit       # exit to the 2nd level - dash
DEPTH: 3
exit
$ depth && exit               # exit to the 1st level - bash
DEPTH: 2
User@Ubuntu:~$ depth && exit  # stay at the 1st level - bash
DEPTH: 1
User@Ubuntu:~$ depth && exit  # stay at the 1st level - bash
DEPTH: 1

So sánh bằng các giải pháp khác: Tôi đã dành thêm thời gian để tìm hiểu một số điểm yếu của các phương pháp được cung cấp ở đây. Tôi đã có thể tưởng tượng hai trường hợp sau (chữ in hoa là cần thiết để làm nổi bật cú pháp tốt hơn):

  • Khi suhoặc sudo -icó liên quan:

    User@Ubuntu:~$ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh|su|sudo)\>'
    1
    User@Ubuntu:~$ echo $SHLVL
    1
    User@Ubuntu:~$ depth
    DEPTH: 1
    
    User@Ubuntu:~$ su spas
    Password:
    
    Spas@Ubuntu:~$ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh|su|sudo)\>'
    1
    Spas@Ubuntu:~$ echo $SHLVL
    2
    Spas@Ubuntu:~$ depth
    DEPTH: 2
    
    Spas@Ubuntu:~$ sudo -i
    [sudo] password for spas:
    
    Root@Ubuntu:~# ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh|su|sudo)\>'
    3
    Root@Ubuntu:~# echo $SHLVL
    1
    Root@Ubuntu:~# depth
    DEPTH: 3
  • Khi có một quá trình nền được đưa ra:

    User@Ubuntu:~$ bash
    User@Ubuntu:~$ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>'
    2
    User@Ubuntu:~$ echo $SHLVL
    2
    User@Ubuntu:~$ depth
    DEPTH: 2
    
    User@Ubuntu:~$ while true; do sleep 10; done &
    [1] 10886
    User@Ubuntu:~$ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>'
    3
    User@Ubuntu:~$ echo $SHLVL
    2
    User@Ubuntu:~$ depth
    DEPTH: 2
    
    # Note: $SHLVL is not supported only by sh/dash.  
    #       It works with all other tested shells: bash, zsh, csh, tcsh, ksh
    
    User@Ubuntu:~$ sh
    $ ps | grep -Ec '\<(bash|zsh|sh|dash|ksh|csh|tcsh)\>'
    4
    $ echo $SHLVL
    2
    $ depth
    DEPTH: 3

Bây giờ tôi đang hoang mang về đầu ra tôi có trên hệ thống của mình : systemd───xfce4-terminal───bash───pstree. Tại sao lại là cách này?
val

1
@val: systemd là tiến trình init, cha mẹ của tất cả các tiến trình khác. Bạn rõ ràng đang sử dụng xfce4-terminal, đã khởi chạy một bashshell, trong đó bạn chạy pstree, trong đó báo cáo chính nó và cha mẹ của nó. Nếu bạn có nghĩa là thiếu các bước giữa systemd và xfce4-terminal, thì có thể là bất cứ thứ gì đã khởi chạy xfce4-terminal đều chết hoặc bị từ chối, trong trường hợp đó, nó sẽ được thừa kế bởi init.
Nick Matteo

Lý do nào để không đọc SHLVL? Tính di động trên các quy trình và hệ thống, tôi giả sử, nhưng sau đó pstree có thể không được cài đặt ..
D. Ben Knoble

Xin chào, @ D.BenKnoble, vì nó được thảo luận dưới câu trả lời của @ egmont , $SHLVLkhông được hỗ trợ bởi một số vỏ. Cụ thể hơn, theo môi trường từ bản demo ở trên, nó không chỉ được hỗ trợ bởi sh( dash) - và lớp vỏ này hoàn toàn không được tính bởi biến này. Mặt khác, pstreemột phần của gói psmisc cũng cung cấp fuser, killallvà một số khác - nó là thành phần chính của Ubuntu - Tôi chưa cài đặt nó trên các hệ thống được đề cập trong câu trả lời này.
pa4080

30

Kiểm tra giá trị của SHLVLbiến shell:

echo $SHLVL

Trích dẫn từ bashtrang hướng dẫn của:

SHLVL  Incremented by one each time an instance of bash is started.

Nó cũng được hỗ trợ bởi zsh.


4
Nhưng sh không được tính, vì vậy ví dụ đưa ra, với sh, sẽ không tăng SHLVL. Tuy nhiên, đây là điều có thể hữu ích cho những người không chuyển đổi vỏ quá nhiều
ubfan1

3
@ ubfan1 trừ khi có định nghĩa vimrc ghi đè, tôi :shmặc định là vỏ đăng nhập của người dùng (đây thực sự là một dạng viết tắt :shellthay vì tên của một nhị phân vỏ cụ thể)
Steelepage

3
Tôi không quen thuộc với các chi tiết của vim, nhưng tôi đã thử :shtừ vimtrước khi đăng câu trả lời này và nó đã tăng mức độ vỏ cho tôi. Shell đăng nhập của tôi là bash.
egmont

9

Theo tôi .bashrc, tôi sử dụng $SHLVLđể điều chỉnh $PS1, bằng cách thêm +các dấu "" vào $SUBSHELLbiến của mình :

...
# set a variable to reflect SHLVL > 1 (Ubuntu 12.04)
if [[ $SHLVL -gt 1 ]] ; then
    export SUBSHELL="${SUBSHELL:+$SUBSHELL}+"
else
    export SUBSHELL=""
fi
...

if [[ "$color_prompt" = yes ]]; then
#             chroot?                       Depth      green       user@host nocolor  :   green      $PWD  red      (status) off   $ or # space             
    PS1='${debian_chroot:+($debian_chroot)}${SUBSHELL}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[1;31m\]($?)\[\033[00m\]\$ '
else
    PS1='${debian_chroot:+($debian_chroot)}${SUBSHELL}\u@\h:\w\$ '
fi
...

Sau đó, tôi có thể thấy tôi sâu sắc như thế nào:

walt@bat:~(1)$ ed foo
263
!bash
+walt@bat:~(0)$ bash
++walt@bat:~(0)$ bash
+++walt@bat:~(0)$ exit
exit
++walt@bat:~(0)$ exit
exit
+walt@bat:~(0)$ exit
exit
!
q
walt@bat:~(0)$ 

4

ôi

# Count the occurrence of (sh)ells.
DEPTH_REGEX='^(ash|bash|busybox|csh|dash|fish|mksh|sh|tcsh|zsh)$'

DEPTH=$(/bin/ps -s $(/bin/ps -p $$ -osid --no-headers) -ocomm --no-headers | \
awk -v R=$DEPTH_REGEX '{for (A=1; A<=(NR-2); A++) {if ($A ~ R) {B++}}} END {print B}')

pgrep:

DEPTH=$(/usr/bin/pgrep -c -s $(/bin/ps -p $$ -osid --no-headers) '^(ash|bash|busybox|csh|dash|fish|mksh|sh|tcsh|zsh)$')

Bạn có thể đặt một trong hai phiên bản trong một tệp và sử dụng nguồn để cung cấp $ DEPTH.

# Set 256 colors in terminal.
if [ -x /usr/bin/tput ] && [ "$(SHELL=/bin/sh tput colors)" -ge 8 ]; then
    export TERM="xterm-256color"
fi

# change these if you don't dig my colors!

NM="\[\033[0;1;37m\]"   #means no background and white lines
HI="\[\033[0;37m\]"     #change this for letter colors
SI="\[\033[38;5;202m\]" #this is for the current directory
NI="\[\033[0;1;30m\]"   #for @ symbol
IN="\[\033[0m\]"

# Count the occurrence of (sh)ells.
source /usr/share/shell-depth/depth

PS1="${NM}[${HI}\u${NI}@${HI}\h ${SI}\w${NM} \A](${HI}${DEPTH}${NM}): ${IN}"

2

Bạn chỉ có thể sử dụng psmà không cần bất kỳ đối số bổ sung nào để xem toàn bộ ngăn xếp shell (bao gồm cả đối số hiện tại). Nó cũng sẽ hiển thị tất cả các công việc nền mà bạn đã bắt đầu cũng như pschính nó, nhưng nó có thể cho bạn một ước tính sơ bộ về mức độ sâu sắc của bạn.


Điều này hoạt động { echo hello world; ps; } &để chứng minh pscâu trả lời ở trên.
WinEunuuchs2Unix

@ WinEunuuchs2Unix, ý tôi là như thế này: paste.ubfox.com/p/6Kfg8TqR9V
pa4080

Có cách nào để bắt chước pstree -s $$ với ps không?
bac0n
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.