`ซึ่ง 'แต่ทั้งหมด


19

ฉันคิดว่าคนส่วนใหญ่คุ้นเคยกับwhichคำสั่งและฉันใช้มันบ่อยๆ ฉันเพียงแค่วิ่งเข้าไปในสถานการณ์ที่ฉันอยากรู้ไม่ได้เป็นเพียงที่คำสั่งเป็นครั้งแรกในเส้นทางของฉัน แต่หลายวิธีและสถานที่ที่ทุกคำสั่งในเส้นทางของฉันทั้งหมดที่มี ฉันลองใช้หน้าคน (พิมพ์man whichทำให้ฉันหัวเราะ) แต่ไม่เห็นอะไรเลย


1
which --allในระบบของฉันมันเป็นสิ่งแรกที่แสดงบนหน้าคน:
Shawn J. Goff

2
ในเหมือง (Linux) which -aเป็นเพียง
ผู้ใช้ที่ไม่รู้จัก

คำตอบ:


23

ในบางระบบwhich -aแสดงการแข่งขันทั้งหมด หากเปลือกของคุณเป็นทุบตีหรือzsh¹คุณสามารถใช้typeแทน: type fooแสดงการจับคู่ครั้งแรกและtype -a fooแสดงการแข่งขันทั้งหมด สามคำสั่งtype, whichและwhenceทำส่วนใหญ่เป็นสิ่งเดียวกัน; พวกเขาแตกต่างกันระหว่าง shells และระบบปฏิบัติการในสภาพพร้อมใช้งานตัวเลือกและสิ่งที่พวกเขารายงาน typeพร้อมใช้งานเสมอและแสดงชื่อเหมือนคำสั่งที่เป็นไปได้ทั้งหมด (นามแฝงคำหลักเชลล์ในตัวฟังก์ชันและคำสั่งภายนอก)

วิธีเดียวที่สามารถพกพาได้อย่างเต็มที่เพื่อแสดงการแข่งขันทั้งหมดคือการแยกวิเคราะห์$PATHตัวเอง นี่คือเชลล์สคริปต์ที่ทำสิ่งนี้ ถ้าคุณทำมันฟังก์ชั่นเปลือกให้แน่ใจว่าจะใส่ร่างกายของฟังก์ชั่นในวงเล็บ (เพื่อให้การเปลี่ยนแปลงIFSและset -fไม่ได้หลบหนีฟังก์ชั่น) และการเปลี่ยนแปลงไปexitreturn

#!/bin/sh
set -f       # disable globbing
IFS=:        # break words at : only
not_found=1
for d in $PATH; do
  if [ -f "$d/$x" ] && [ -x "$d/$x" ]; then
    printf '%s\n' "$d/$x"
    not_found=0
  fi
done
exit $not_found

¹ หรือ ksh 93 ตามเอกสารแม้ว่า ksh 93s + 2008-01-31 จะพิมพ์เฉพาะนัดแรกเมื่อฉันลอง


ว่ารหัสไม่ทำงานอย่างถูกต้องหากมีส่วนประกอบว่างในsh $PATHนอกจากนี้ยังทราบว่า$IFSเป็นเขตที่คั่น (ในเปลือกหอย POSIX อย่างน้อย) ขณะที่อยู่ใน$PATHลำไส้ใหญ่จะถูกใช้เป็นสนามคั่น ดูwhichสคริปต์ที่พบใน Debian สำหรับการใช้งานที่ถูกต้อง
Stéphane Chazelas

typebuiltin ในksh93u+ 2012-08-01ดูเหมือนว่าจะทำงานอย่างถูกต้อง
Stéphane Chazelas

5

แฟล็ก --all หรือ -a จะแสดงรายการที่ตรงกันทั้งหมดในเส้นทางของคุณและชื่อแทน (อย่างน้อยใน Fedora, Ubuntu และ CentOS):

which -a which

บน AIX และ Solaris สิ่งนี้จะทำให้คุณใกล้ชิด:

echo "$PATH" | sed -e 's/:/ /g' | \
while read -r p; do find "$p" -type f -name "which"; done

คุณต้องใส่เครื่องหมายอัญประกาศล้อมรอบการแทนที่พารามิเตอร์มิฉะนั้นสคริปต์จะไม่ทำงานหาก$PATHมีช่องว่างหรือช่องว่างตัวอักษรกลม read -rจำเป็นต้องรับมือกับแบ็กสแลช นี่ไม่ใช่วิธีการที่ดีเพราะfindจะใช้เวลานานและอาจส่งคืนการจับคู่แบบเสแสร้งหากไดเรกทอรีใน$PATHมีไดเรกทอรีย่อย โชคดีที่findไม่มีประโยชน์ที่นี่; เห็นคำตอบของฉัน
Gilles 'หยุดความชั่วร้าย'

ฉันรู้ว่ารู้สึกผิดเพราะมันช้าในไดเรกทอรีที่ซ้อนกัน Globbing และช่องว่างใน $ PATH? eww แต่คุณพูดถูก (แม้ว่าคุณจะดีพอที่จะไม่พูดมาก): หนึ่งในสายการบินเขียนได้ไม่ดี
Eli Heady

1

หากคุณไม่มีการwhichสนับสนุน-aหรือwhenceมีอยู่ให้หมุนของคุณเอง:

#!/bin/sh -f

IFS=":"
for PART in $PATH
do
  if test -x "$PART/$1"
  then
    echo $PART/$1
  fi
done

คุณกำลังขาดหายไปset -fเพื่อปิด globbing $PATHในที่ไม่มีการป้องกัน test -fไม่เพียงพอเนื่องจากมีเพียงไฟล์ปฏิบัติการที่ต้องการได้ที่นี่ test -xคุณจำเป็นต้อง อืมฉันรู้ว่าฉันลืมการทดสอบไฟล์ปกติในสคริปต์ของฉัน
Gilles 'SO- หยุดความชั่วร้าย'

@Gilles: แก้ไขตามเคล็ดลับของคุณ ฉันทั้งหมดถูกต้อง แต่ฉันคิดwhence README.txtว่าไม่น่าเป็นwhence "file* wi?h we!rd name"ไปได้ $PATHเพียงแค่พยายามที่จะแสดงให้เห็นว่าง่ายก็คือการสำรวจ
MattBianco

0

ksh และ zsh มี "whence" เป็นเชลล์ในตัว whence -aทำสิ่งที่คุณต้องการภายใต้ zsh:

 7:27AM 7 % whence -a cat
/usr/bin/cat
/bin/cat
/usr/bin/cat
/bin/cat

ฉันต้องทำความสะอาด PATH ใน zsh ฉันมีข้อมูลซ้ำซ้อนมากมาย whence -aทำงานแตกต่างกันภายใต้ ksh:

$ whence -a cat
cat is a tracked alias for /usr/bin/cat

ฉันต้องบอกว่านั่นเป็นพฤติกรรมที่มีประโยชน์เช่นกัน

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