Bash: Cách xác định xem thiết bị đầu cuối có được mở bởi ứng dụng của bên thứ ba không


9

Tôi muốn tập lệnh bash của tôi (cụ thể là của tôi ~/.bashrc) chỉ làm một cái gì đó nếu thiết bị đầu cuối được tôi mở trực tiếp và làm một cái gì đó khác nếu nó được mở thông qua một ứng dụng, ví dụ như Mã VS. Làm thế nào tôi có thể xác định trường hợp là gì? Có một biến cho điều đó? Cảm ơn trước.


1
Có một cách, một phản hồi đầu tiên của tôi sẽ là ví dụ thứ hai trong Askubfox.com/a/1042727/295286 . Hãy thử mở VS và chạy envlệnh. Xem nếu có một biến cụ thể VS mà chúng ta có thể sử dụng.
Sergiy Kolodyazhnyy

1
Nếu không có gì, hãy thử theo cách khác: Xem trình giả lập thiết bị đầu cuối của bạn có đặt biến không. Tôi sử dụng yakuakevà có một bộ biến PULSE_PROP_OVERRIDE_application.name=Yakuake, và xtermbộ XTERM_VERSION=XTerm(322)trên máy của tôi.
tráng miệng

@SergiyKolodyazhnyy Bạn có thể viết câu trả lời cho cách tiếp cận biến môi trường không?
tráng miệng

@dPlay Tôi sẽ, nhưng tôi chưa cài đặt VS, OP cũng không phản hồi nếu có bất kỳ biến môi trường cụ thể nào mà chúng tôi có thể bám vào.
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy Tôi cũng không có, nhưng tiêu đề câu hỏi cho biết ứng dụng của bên thứ ba và tôi cho rằng nó hoạt động giống như bất kỳ trình giả lập thiết bị đầu cuối nào - Tôi nghĩ rằng một câu trả lời như env >env_term1trong một trình giả lập, env >env_term2trong phần hai và cách sử dụng những gì diff env_term{1,2}nói rất hữu ích. Sau khi tất cả, OP nói ví dụ VS Mã .
tráng miệng

Câu trả lời:


10

Bạn có thể có thể làm điều đó bằng cách quay trở lại tổ tiên của vỏ và tìm hiểu xem nó đã được bắt đầu bởi thứ gì đó tương đương với "bạn" hay chương trình khác.

Nhận PID của shell (ID tiến trình) và từ đó PPID (ID tiến trình cha) của nó. Tiếp tục đi lên cho đến khi bạn nhận được một cái gì đó cho bạn biết nó đến từ đâu. Bạn có thể cần thử nghiệm trên hệ thống của mình - ít nhất, tôi không biết liệu nó có phổ biến không.

Ví dụ, trên hệ thống của tôi, hãy lấy PID của trình bao và sử dụng psđể hiển thị rằng bash:

$ echo $$
18852
$ ps --pid 18852
  PID TTY          TIME CMD
18852 pts/1    00:00:00 bash

Nhận PPID năm 18852:

$ ps -o ppid= -p 18852
18842

Tìm hiểu PPID (18842) là gì:

$ ps --pid 18842
  PID TTY          TIME CMD
18842 ?        00:00:02 gnome-terminal

Chúng ta có thể thấy đó là gnome-terminal, tức là cửa sổ trình mô phỏng / thiết bị đầu cuối. Có lẽ điều đó đủ tốt cho bạn, nếu trình bao của bạn được chương trình kia khởi chạy không chạy trong cửa sổ giả lập thiết bị đầu cuối.

Nếu nó không đủ tốt, hãy lên một cấp độ khác:

$ ps -o ppid= -p 18842
 2313
$ ps --pid 2313
  PID TTY          TIME CMD
 2313 ?        00:00:00 init

Điều này cho chúng tôi biết rằng gnome-terminalđã được bắt đầu bởi init. Tôi nghi ngờ vỏ của bạn bắt đầu bởi một chương trình khác sẽ có một cái gì đó khác nhau ở đó.


... hoặc có lẽ bằng cách đi lên kết quả củapstree -s $$
Steeldo

9
"Điều này cho chúng tôi biết rằng gnome-terminal đã được khởi động bởi init" Tôi thấy rằng init sẽ không khởi động được các cửa sổ terminal. Thay vào đó, bất cứ thứ gì bắt đầu gnome-terminal đều chết, và gnome-terminal được cấp lại cho init. Kiểm tra gnome-terminal, có vẻ như nó tăng gấp đôi. Vì vậy, khi nó thực thi, đầu tiên nó tự rèn và giết quá trình ban đầu, tiếp tục trong quy trình mới.
JoL

@JoL Điểm công bằng. initTuy nhiên, quá trình đó không phải là 1, không chắc điều đó có thay đổi gì không.
kasperd

Cảm ơn rất nhiều! Tôi đã có thể phát hiện ra rằng cả Mã VS và Eclipse đều không chạy thiết bị đầu cuối như một đứa trẻ gnome-terminal. Tôi thực hiện lệnh của tôi dưới if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...và nó đã làm việc.
PaperBag

9

Theo như Visual Studio Code, rõ ràng có một cách để đặt các biến môi trường bổ sung cho thiết bị đầu cuối tích hợp . Vì vậy, hãy thiết lập Visual Studio để sử dụng cấu hình này:

"terminal.integrated.env.linux": {
  "visual_studio": "true"
}

Và trong ~/.bashrc:

if [ -n "$visual_studio" ]; then
    # do something for Visual Studio
else
    # do something else for other types of terminal
fi

Nói chung, bạn có thể dựa vào môi trường được đưa ra cho bashquá trình. Ví dụ, các $TERMbiến , và chạy một tương tự if..then...else...fichi nhánh cho [ "$TERM" = "xterm" ]hay cái gì khác. Trên cơ sở từng trường hợp, bạn có thể điều tra sự khác biệt trong môi trường thông qua việc chạy envtrong mỗi bảng điều khiển, lưu nó vào tệp như trong env > output_console1.txtdiff output_console1.txt output_console2.txtnhư được đề xuất bởi món tráng miệng trong các bình luận .


$Env:varkhông phải là cú pháp cho các biến môi trường trong Bash. Điều này trông giống như một điều Powershell với tôi.
Dietrich Epp

@DietrichEpp Vâng, ban đầu tôi đã nghiên cứu các cách để đặt các biến môi trường bổ sung trong Visual Studio, nhưng bỏ qua rằng các câu trả lời đang sử dụng PowerShell. Như vậy $foolà đủ. Cà phê có lẽ là không đủ.
Sergiy Kolodyazhnyy

Đối với trường hợp chung của các chương trình bên thứ 3 không có cài đặt env, bạn có thể đặt var env tùy chỉnh trong trình bao bọc trước khi chạy chương trình. Xem câu trả lời của tôi .
Peter Cordes

2

Nếu bạn đang nói về một ứng dụng của bên thứ ba cụ thể, thì hãy sử dụng biến môi trường. Hầu hết các chương trình sẽ chuyển qua toàn bộ môi trường không thay đổi khi chúng rẽ nhánh + thực hiện các quy trình mới.

Vì vậy, hãy bắt đầu ứng dụng này với một var env tùy chỉnh mà bạn có thể kiểm tra . ví dụ: tạo một bí danh cho nó như thế nào alias vs=RUNNING_FROM_VSCODE=1 VSCode, hoặc tạo một tập lệnh bao bọc như thế này:

#!/bin/sh
export RUNNING_FROM_VSCODE=1
exec VSCode "$@"

Sau đó, trong bạn .bashrc, bạn có thể làm

if (($RUNNING_FROM_VSCODE)); then
   echo "started from inside VSCode"
   # RUNNING_FROM_VSCODE=0  # optional if you only want the immediate child
fi

Một câu lệnh số học bash (( ))là đúng nếu biểu thức ước lượng thành một số nguyên khác không (đó là lý do tại sao tôi sử dụng 1ở trên). Chuỗi rỗng (đối với var env unset) là sai. Thật tuyệt vời cho các biến bashean, nhưng bạn có thể dễ dàng sử dụng truevà kiểm tra nó với POSIX truyền thống

if [ "x$RUNNING_FROM_VSCODE" = "xtrue" ]; then
   echo "started from inside VSCode"
fi

Nếu ứng dụng của bạn chủ yếu xóa môi trường cho trẻ em , nhưng vẫn $PATHkhông thay đổi, bạn có thể sử dụng ứng dụng này trong trình bao bọc của mình:

#!/bin/sh
export PATH="$PATH:/dev/null/RUNNING_FROM_VSCODE"
exec VSCode "$@"

và kiểm tra xem nó có khớp mẫu như bash [[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]để kiểm tra xem việc tước hậu tố từ PATH có làm thay đổi nó không.

Điều này sẽ vô hại thực hiện một tìm kiếm thư mục bổ sung khi chương trình đang tìm kiếm các lệnh bên ngoài không tìm thấy. /dev/nullchắc chắn không phải là một thư mục trên bất kỳ hệ thống nào, vì vậy việc sử dụng như một thư mục không có thật sẽ nhanh chóng dẫn đến kết quả ENOTDIRnếu các tìm kiếm PATH không tìm thấy những gì họ đang tìm kiếm trong các mục PATH trước đó.


Các kịch bản trình bao bọc thường là một cách tiếp cận hợp lý, do đó +1. Nhược điểm nhỏ duy nhất là nếu bạn có 3 chương trình, bạn có thể muốn có 3 tập lệnh trình bao bọc hoặc một tập lệnh trình bao bọc lấy 3 đối số khác nhau, điều này có thể làm cho nó tẻ nhạt. Tuy nhiên, đó là một cách tiếp cận vững chắc.
Sergiy Kolodyazhnyy

1

Đây là 2 xu của tôi. Chỉ cần thêm nó vào của bạn .bashrc. Thay thế terminalsbằng thiết bị đầu cuối yêu thích của bạn và exportlệnh bằng của bạn.

run_in_terminal(){
  local parent_command="$(ps --no-headers --pid $PPID -o command | awk '{print $1;}')"
  local parent="$(basename $parent_command)"
  local terminals=( gnome-terminal st xterm ) # list your favorite terminal here
  if [[ ${terminals[*]} =~ ${parent} ]]; then
    # Your commands to run if in terminal
    export MY_VAR_IN_TERMINAL="test"
  fi
}
run_in_terminal

Điều này sẽ không hoạt động với mô hình máy chủ-máy khách của gnome-terminal.
egmont
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.