ฉันจะรันคำสั่งใน bash หลังจากการเปลี่ยนแปลงใด ๆ ใน $ PWD ได้อย่างไร


10

zsh มีฟังก์ชั่น hook ที่ดีรวมถึงchpwdการใช้งานฟังก์ชั่นหลังจากผู้ใช้เปลี่ยนไดเรกทอรี

# zsh only
function greet() { echo 'hi'; }
chpwd_functions+=("greet")
cd .. # hi
pushd # hi
popd  # hi

ฉันพยายามเลียนแบบสิ่งนั้นด้วยการทุบตี

ข้อ จำกัด :

  • มันต้องใช้งานได้ทั้งกระสุนแบบโต้ตอบและแบบไม่โต้ตอบซึ่งฉันคิดว่าหมายความว่ามันไม่สามารถพึ่งพาอะไรได้ $PROMPT_COMMAND
  • ไม่สามารถกำหนดใหม่ได้cdเพราะฉันต้องการให้มันทำงานกับคำสั่งใด ๆ ที่เปลี่ยนไดเรกทอรี (เช่นpushdและpopd)
  • มันจะต้องทำงานหลังจากคำสั่งของผู้ใช้ดังนั้นจึงtrap "my_function" DEBUGใช้งานไม่ได้เว้นแต่ฉันจะสามารถพูดได้ที่นั่น "ก่อนอื่นให้$BASH_COMMANDเราติดกับดักจากนั้นก็ทำเช่นนี้ ... " ฉันเห็นว่าฉันสามารถหลีกเลี่ยงการทำงานอัตโนมัติ$BASH_COMMAND หาก extdebugเปิดใช้งานและฟังก์ชั่นการดักจับคืนค่า 1 แต่ฉันไม่คิดว่าฉันต้องการบังคับextdebugและการกลับมา1ใช้คำสั่งที่ประสบความสำเร็จ

ส่วนสุดท้าย - "เรียกใช้หลังจากคำสั่งของผู้ใช้" - เป็นสิ่งที่ฉันนิ่งงันในขณะนี้ ถ้าฉันสามารถเรียกใช้ฟังก์ชั่นหลังจากแต่ละคำสั่งฉันสามารถให้มันตรวจสอบว่าไดเรกทอรีมีการเปลี่ยนแปลงตั้งแต่ที่เราตรวจสอบล่าสุด เช่น:

function check_pwd() {
  # true in a new shell (empty var) or after cd
  if [ "$LAST_CHECKED_DIR" != "$PWD" ]; then
    my_function
  fi
  LAST_CHECKED_DIR=$PWD
}

ฉันไปถูกทางหรือมีวิธีที่ดีกว่า ฉันจะรันคำสั่งใน bash หลังจากที่ผู้ใช้เปลี่ยนไดเรกทอรีได้อย่างไร


3
ทำไมไม่ redefine cd, pushdและpopd? มีวิธีอื่นอีกกี่วิธีในการเปลี่ยนไดเรกทอรี
jw013

@ jw013 รหัสนี้มีวัตถุประสงค์เพื่อเข้าสู่โครงการโอเพนซอร์ซซึ่งผู้ดูแลระบบได้ระบุไว้เป็นพิเศษโดยไม่ได้นิยามใหม่cdเป็นหลักการ
นาธานลอง

นอกจากนี้ - "มีวิธีอื่นอีกกี่วิธีในการเปลี่ยนไดเรกทอรี" - ฉันไม่รู้ซึ่งเป็นอีกสาเหตุหนึ่งที่ฉันไม่ต้องการพึ่งพารายชื่อพวกเขาอย่างชัดเจน
นาธานลอง

ทำไมคุณถึงต้องการทำเช่นนี้? ฟังก์ชั่นของคุณอาจเบรกโปรแกรมจำนวนมาก (C, Java, .. ) ในสคริปต์ฉันใช้MYBIN=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P )โปรดอย่าเปลี่ยนคำสั่ง Unix ที่เชื่อถือได้
วอลเตอร์

1
@NathanLong สำหรับระบบปฏิบัติการของฉันเท่านั้น ระบบปฏิบัติการดูเหมือนไม่เกี่ยวข้องที่นี่ ระบบปฏิบัติการมีความสำคัญหรือไม่? มันเป็นเชลล์ที่สำคัญสำหรับคำถามของคุณและคุณดูเหมือนจะถามโดยเฉพาะเกี่ยวกับbashสิ่งที่ใช้งานได้ดีในระบบปฏิบัติการทั้งหมดที่ทำงานอยู่
jw013

คำตอบ:


2

ไม่มีทางที่ตรงตามข้อ จำกัด เหล่านี้

ดูเหมือนว่าจะไม่มีวิธีแก้ไขปัญหานี้ในการทุบตีกับข้อ จำกัด ของฉัน โดยทั่วไปการแก้ปัญหาที่เป็นไปได้คือ:

  • แทนที่cd, pushdและpopdเพื่อให้คำสั่งใด ๆ ที่มีการเปลี่ยนแปลงไดเรกทอรีแรกจะเรียกใช้ฟังก์ชั่นเบ็ด แต่สิ่งนี้สามารถสร้างปัญหาได้เนื่องจาก 1) การแทนที่จะต้องระมัดระวังในการแท็บที่สมบูรณ์เช่นคำสั่งเดิมและส่งคืนรหัสทางออกเดียวกันและ 2) หากมีมากกว่าหนึ่งเครื่องมือที่ใช้วิธีการนี้พวกเขาไม่สามารถเล่นด้วยกันได้ดี
  • แทนที่คำสั่งทั้งหมดที่อาจทำงานด้วยการเปลี่ยนแปลงสภาพแวดล้อมเพื่อเรียกใช้ฟังก์ชั่นเบ็ดก่อน นี่เป็นเรื่องยากเพราะมีคำสั่งมากมาย
  • trap 'my_functionDEBUG so that every command will run the hook function. This is suboptimal because 1) it runs before every command, 2) it runs *before*cd` ไม่ใช่หลังจาก 3) มีเพียงหนึ่งฟังก์ชันการดีบักเท่านั้นดังนั้นหากเครื่องมืออื่นใช้วิธีนี้พวกเขาจะเล่นด้วยกันไม่ได้
  • กำหนดใหม่$PROMPT_COMMANDเพื่อเรียกใช้ฟังก์ชัน hook ก่อน นี่เป็นสิ่งที่ไม่ดีเพราะมันจะไม่ทำงานในเชลล์ที่ไม่มีการโต้ตอบและเพราะหากเครื่องมืออื่นกำหนดคำสั่ง prompt พวกมันไม่สามารถเล่นด้วยกันได้ดี

ในระยะสั้นดูเหมือนว่าทางออกที่ดีเพียงอย่างเดียวคือถ้าทุบตีจัดหาอะไรบางอย่างเช่นchpwd_functionsเบ็ดของ zshell แต่ดูเหมือนว่าเป็นไปไม่ได้ที่จะจำลองมันอย่างถูกต้อง


1

หากผู้ดูแลไม่ต้องการให้คุณเปลี่ยนคำจำกัดความสำหรับ cd ตัวเลือกอื่นจะเป็นการกำหนดคำสั่งทั้งหมดใหม่ซึ่งใช้สภาพแวดล้อมในไดเรกทอรีนี้:

for c in cmd1 cmd2 cmd3 cmd4 cmd5 ; do
    eval "$c() { check_pwd ; command $c \"\$@\" ; }"
done

สิ่งนี้จะค่อนข้างมีประสิทธิภาพเพราะการกำหนดค่า PWD hook และในไดเรกทอรีจะดำเนินการเมื่อจำเป็นเท่านั้น

ในตัวอย่าง check_pwd ของคุณฉันอาจเปลี่ยน:

my_function

ถึง:

my_function "$PWD"

เพื่อที่จะผ่านใน cwd ใหม่ (อาจเป็นแบบแยกส่วนได้มากขึ้น, ทดสอบได้)


"กำหนดคำสั่งทั้งหมดที่ใช้สภาพแวดล้อมในไดเรกทอรีนี้ใหม่" น่าเสียดายที่ฉันไม่สามารถคาดเดาได้
นาธานลอง

0

ติดตั้งinotify-toolsตามการแจกจ่ายของคุณ

inotifywait -emodify,create,delete -m /path/to/directory | while read line; do service httpd reload; done

ในตัวอย่างของฉันคำสั่งต่อไปนี้จะรีสตาร์ทhttpdหากมีการเปลี่ยนแปลงอะไร (แก้ไข, สร้าง, ลบ) ในไดเรกทอรีที่ระบุ

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