Bash: วิธีการตรวจสอบว่าเทอร์มินัลถูกเปิดโดยแอปของบุคคลที่สาม


9

ฉันต้องการสคริปต์ทุบตีของฉัน (โดยเฉพาะของฉัน~/.bashrc) ที่จะทำอะไรเฉพาะในกรณีที่เปิดสถานีโดยฉันโดยตรงและทำอย่างอื่นถ้ามันถูกเปิดผ่านแอพเช่น VS Code ฉันจะทราบได้อย่างไรว่าเกิดอะไรขึ้น มีตัวแปรสำหรับสิ่งนั้นหรือไม่? ขอบคุณล่วงหน้า.


1
มีการเรียงลำดับของวิธีคือการตอบสนองครั้งแรกของฉันจะไปกับตัวอย่างที่สองใน askubuntu.com/a/1042727/295286 ลองเปิด VS และเรียกใช้envคำสั่ง ดูว่ามีตัวแปรเฉพาะ VS ที่เราสามารถใช้ได้หรือไม่
Sergiy Kolodyazhnyy

1
ถ้าไม่มีอะไรให้ลองวิธีอื่นดู: ดูว่าเทอร์มินัลอีมูเลเตอร์ของคุณตั้งค่าตัวแปรได้หรือไม่ ฉันใช้yakuakeและมีPULSE_PROP_OVERRIDE_application.name=Yakuakeชุดตัวแปรและxtermตั้งค่าXTERM_VERSION=XTerm(322)บนเครื่องของฉัน
ของหวาน

@SergiyKolodyazhnyy คุณช่วยเขียนคำตอบสำหรับวิธีการตัวแปรสภาพแวดล้อมได้มั้ย
ของหวาน

@ ของหวานที่ฉันต้องการ แต่ฉันไม่ได้ติดตั้ง VS ทั้ง OP ไม่ตอบถ้ามีตัวแปรสภาพแวดล้อมใด ๆ ที่เราสามารถยึด
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy ฉันไม่มี แต่ชื่อคำถามบอกว่าแอปของบุคคลที่สามและฉันคิดว่ามันทำงานได้เหมือนเทอร์มินัลอีมูเลเตอร์ใด ๆ - ฉันคิดว่าคำตอบเช่นenv >env_term1เดียวกับอีมูเลเตอร์env >env_term2ในอีกอันหนึ่งและวิธีใช้สิ่งที่diff env_term{1,2}กล่าวว่ามีประโยชน์มาก ท้ายที่สุดOP พูดเช่น VS Code
ของหวาน

คำตอบ:


10

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

รับ PID ของเชลล์ (ID กระบวนการ) และจากนั้น PPID ของมัน (ID กระบวนการหลัก) ขึ้นไปเรื่อย ๆ จนกว่าคุณจะไปถึงสิ่งที่บอกคุณว่ามันมาจากไหน คุณอาจต้องทดลองกับระบบของคุณ - อย่างน้อยฉันก็ไม่รู้ว่ามันจะเป็นแบบสากลหรือไม่

ตัวอย่างเช่นในระบบของฉันรับ PID ของเชลล์และใช้psเพื่อแสดงว่าbash:

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

รับ PPID ของ 18852:

$ ps -o ppid= -p 18852
18842

ค้นหาว่า PPID (18842) คืออะไร:

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

เราสามารถเห็นได้ว่ามันคือ gnome-terminal เช่นหน้าต่างเทอร์มินัลอีมูเลเตอร์ / เทอร์มินัล อาจจะดีพอสำหรับคุณถ้าเชลล์ของคุณเปิดตัวโดยโปรแกรมอื่นไม่ทำงานในหน้าต่างเทอร์มินัลอีมูเลเตอร์

หากยังไม่ดีพอขึ้นไปอีกระดับ:

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

นี้บอกเราว่าเริ่มต้นจากgnome-terminal initฉันสงสัยว่าเชลล์ของคุณเริ่มต้นโดยโปรแกรมอื่นจะมีบางอย่างที่แตกต่างกัน


... หรืออาจจะด้วยการเดินตามผลลัพธ์ของpstree -s $$
steeldriver

9
"สิ่งนี้บอกเราว่า gnome-terminal เริ่มต้นโดย init" ฉันคิดว่าไม่น่าเป็นไปได้ที่ init จะเริ่มต้นหน้าต่างเทอร์มินัล แต่สิ่งที่เริ่มต้นด้วยคำพังเพย - เทอร์มินัลก็ตาย ตรวจสอบ gnome-terminal out ดูเหมือนว่าจะเป็นสองเท่าส้อม ดังนั้นเมื่อมีการดำเนินการมันจะทำการแยกตัวเองและฆ่ากระบวนการเดิมโดยดำเนินการต่อในกระบวนการใหม่
JoL

@JoL จุดประสงค์ ว่าinitกระบวนการไม่ได้ pid 1 แต่ไม่แน่ใจว่าจะเปลี่ยนอะไร
kasperd

ขอบคุณมาก! ผมสามารถที่จะตรวจสอบว่าทั้ง VS รหัสมิได้ Eclipse gnome-terminalรันมินัลเป็นลูกของ ฉันดำเนินการคำสั่งของฉันภายใต้if [ $(pstree -s $$ | grep "gnome-terminal" -c) -gt 0 ]; then ...และใช้งานได้
PaperBag

9

เท่าที่ Visual Studio รหัสไปมีเห็นได้ชัดว่าเป็นวิธีการตั้งค่าตัวแปรสภาพแวดล้อมเพิ่มเติมสำหรับขั้วแบบบูรณาการ ดังนั้นตั้งค่า Visual Studio เพื่อใช้การกำหนดค่านี้:

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

และภายใน~/.bashrc:

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

โดยทั่วไปคุณสามารถพึ่งพาสภาพแวดล้อมที่กำหนดให้กับbashกระบวนการ ยกตัวอย่างเช่นตัวแปรและเรียกคล้ายสาขาหรือสิ่งอื่นใด บนพื้นฐานกรณีต่อกรณีที่คุณสามารถตรวจสอบความแตกต่างในสิ่งแวดล้อมผ่านการทำงานในแต่ละคอนโซลบันทึกว่าจะเป็นไฟล์ในและแนะนำโดยขนมในความคิดเห็น$TERMif..then...else...fi[ "$TERM" = "xterm" ]envenv > output_console1.txtdiff output_console1.txt output_console2.txt


$Env:varไม่ใช่ไวยากรณ์สำหรับตัวแปรสภาพแวดล้อมใน Bash นี่มันดูเหมือน Powershell สำหรับฉัน
Dietrich Epp

@DietrichEpp ใช่ฉันเคยค้นคว้าวิธีตั้งค่าตัวแปรสภาพแวดล้อมเพิ่มเติมใน Visual Studio แต่มองข้ามว่าคำตอบนั้นใช้ PowerShell ดังนั้น$fooก็พอ กาแฟอาจไม่เพียงพอ
Sergiy Kolodyazhnyy

สำหรับกรณีทั่วไปของโปรแกรมของ บริษัท อื่นที่ไม่มีการตั้งค่า env คุณสามารถตั้งค่า env var แบบกำหนดเองใน wrapper ก่อนเรียกใช้โปรแกรม ดูคำตอบของฉัน
Peter Cordes

2

หากคุณกำลังพูดถึงแอปของบุคคลที่สามโดยเฉพาะให้ใช้ตัวแปรสภาพแวดล้อม โปรแกรมส่วนใหญ่จะผ่านไปตามสภาพแวดล้อมทั้งหมดไม่เปลี่ยนแปลงเมื่อพวกเขาแยก + exec กระบวนการใหม่

ดังนั้นเริ่มแอพนี้ด้วย env var ที่คุณสามารถตรวจสอบได้ เช่นสร้างนามแฝงสำหรับมันalias vs=RUNNING_FROM_VSCODE=1 VSCodeหรือทำสคริปต์ wrapper เช่นนี้

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

จากนั้นในของ.bashrcคุณคุณสามารถทำได้

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

คำสั่งทางคณิตศาสตร์ทุบตี(( ))เป็นจริงถ้าการแสดงออกประเมินให้เป็นจำนวนเต็มไม่เป็นศูนย์ (ซึ่งเป็นเหตุผลที่ฉันใช้1ข้างต้น) สตริงว่าง (สำหรับ unv env var) เป็นเท็จ มันดีสำหรับตัวแปร bash boolean แต่คุณสามารถใช้trueและตรวจสอบกับ POSIX แบบดั้งเดิมได้อย่างง่ายดาย

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

หากแอปของคุณล้างสภาพแวดล้อมสำหรับลูก ๆ ของมันเป็นส่วนใหญ่แต่ยังคงผ่านไปโดย$PATHไม่มีการเปลี่ยนแปลงคุณสามารถใช้สิ่งนี้ในเสื้อคลุมของคุณ:

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

และตรวจสอบด้วยการจับคู่รูปแบบเช่นทุบตี[[ "${PATH%RUNNING_FROM_VSCODE}" != "$PATH" ]]เพื่อตรวจสอบว่าการถอดคำต่อท้ายจาก PATH เปลี่ยนหรือไม่

การทำเช่นนี้ควรทำการค้นหาไดเรกทอรีพิเศษหนึ่งครั้งโดยไม่เป็นอันตรายเมื่อโปรแกรมค้นหาคำสั่งภายนอกที่ไม่พบ /dev/nullแน่นอนไม่ใช่ไดเรกทอรีในระบบใด ๆ ดังนั้นจึงปลอดภัยที่จะใช้เป็นไดเรกทอรีปลอมที่จะส่งผลอย่างรวดเร็วENOTDIRหากการค้นหา PATH ไม่พบสิ่งที่ต้องการในรายการ PATH ก่อนหน้านี้


สคริปต์ตัวแรปเปอร์มักเป็นวิธีที่เหมาะสมดังนั้น +1 ข้อเสียเล็กน้อยเพียงอย่างเดียวคือถ้าคุณมี 3 โปรแกรมคุณอาจต้องการสคริปต์ wrapper 3 รายการหรือสคริปต์ wrapper สคริปต์หนึ่งรายการซึ่งมี 3 args ที่แตกต่างกันซึ่งสามารถทำให้มันน่าเบื่อ อย่างไรก็ตามมันเป็นแนวทางที่มั่นคง
Sergiy Kolodyazhnyy

1

นี่คือ 2 เซ็นต์ของฉัน .bashrcเพียงเพิ่มของคุณ แทนที่terminalsด้วยเทอร์มินัลที่คุณโปรดปรานและexportสั่งการด้วยของคุณ

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

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