เหตุใดฉันจึงไม่สามารถเปลี่ยนเส้นทางชื่อผลลัพธ์จากคำสั่งเดียวไปยัง“ cd” ได้


27

ฉันพยายามรับcdชื่อไดเรกทอรีที่เปลี่ยนเส้นทางจากคำสั่งอื่น วิธีการเหล่านี้ไม่ทำงาน:

$ echo $HOME | cd
$ echo $HOME | xargs cd

วิธีนี้ใช้ได้ผล:

$ cd $(echo $HOME)

ทำไมชุดคำสั่งแรกไม่ทำงานและมีคำสั่งอื่นที่ล้มเหลวด้วยหรือไม่


คุณหมายถึงคำสั่งอื่น ๆ หรือวิธีการอื่นในการใช้ cd ที่ล้มเหลวด้วยวิธีนี้
Didi Kohen

@DavidKohen ฉันอ้างถึงคำสั่งอื่น ๆ
Jhonathan

ตัวอย่างที่มีชื่อเสียง ได้แก่ ulimit, umask, popd, pushd, set, export และ read
Didi Kohen

คำตอบ:


32

cdไม่ใช่คำสั่งภายนอก - มันเป็นฟังก์ชั่นของเชลล์ในตัว มันทำงานในบริบทของเชลล์ปัจจุบันและไม่ใช่ตามคำสั่งภายนอกในบริบท fork / exec'd เป็นกระบวนการแยกต่างหาก

ตัวอย่างที่สามของคุณใช้งานได้เนื่องจากเชลล์ขยายตัวแปรและการทดแทนคำสั่งก่อนเรียกcdบิวด์อินเพื่อให้cdได้รับค่า${HOME}เป็นอาร์กิวเมนต์

ระบบ POSIX ทำมีไบนารีcd- บนเครื่อง FreeBSD ของฉันก็ที่/usr/bin/cdแต่ก็ไม่ได้ทำในสิ่งที่คุณคิด การเรียกเลขฐานสองcdทำให้เชลล์ทำการแยก / เรียกเลขฐานสองซึ่งจะเปลี่ยนไดเรกทอรีการทำงานเป็นชื่อที่คุณส่ง อย่างไรก็ตามทันทีที่มันทำเช่นนั้นไบนารีจะออกและกระบวนการ fork / / exec'd จะหายไปและนำคุณกลับสู่เชลล์ซึ่งยังอยู่ในไดเรกทอรีก่อนที่คุณจะเริ่มต้น


10

23

cdไม่อ่านอินพุตมาตรฐาน นั่นคือเหตุผลที่ตัวอย่างแรกของคุณไม่ทำงาน

xargsต้องการชื่อคำสั่งนั่นคือชื่อของตัวดำเนินการอิสระ cdจำเป็นต้องเป็นคำสั่งในตัวของเชลล์และจะไม่มีผลกระทบ (นอกเหนือจากการตรวจสอบว่าคุณสามารถเปลี่ยนเป็นไดเรกทอรีนั้นและผลข้างเคียงที่อาจเกิดขึ้นกับมันอาจเป็นเช่นสำหรับไดเรกทอรีที่ติดตั้งอัตโนมัติ) หากเป็นไฟล์ที่ปฏิบัติการได้ นั่นคือเหตุผลที่ตัวอย่างที่สองของคุณไม่ทำงาน


4

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

echo test | cd /

ดังนั้นคุณจะไม่อยู่ในโฟลเดอร์ / หลังจากเชลล์ส่งคืนจากคำสั่งนี้


คำสั่งทั้งหมดในไปป์ไลน์ทำงานในกระบวนการที่แตกต่างกันดังนั้นa | bแม้ว่าaและbจะมีอยู่แล้วภายในอย่างน้อยหนึ่งคำสั่งจะไม่ทำงานในกระบวนการเชลล์ แต่ไม่มีการรับประกันว่าจะใช้อันใด ยกตัวอย่างเช่นใน AT & T ksh, zshหรือbash -O lastpipe, bการเรียกใช้ในกระบวนการเปลือกปัจจุบันดังนั้นรหัสของคุณจะพาคุณไป / มี
Stéphane Chazelas

4

นอกจากคำตอบที่ถูกต้องที่ให้ไปแล้ว: หากคุณรัน bash และต้องการค้นหาคำสั่ง "like" เช่น cdคุณสามารถใช้type

$ type cd
cd is a shell builtin

หรือทำไมไม่:

$ type time
time is a shell keyword

ในขณะที่ตัวอย่างเวลา gnu ปกติรวมอยู่ในการกระจายที่คุณชื่นชอบแล้ว

$ which time
/usr/bin/time

โอเคคุณเข้าใจแล้วถ้าเป็นประเภทอะไร

$ type type
type is a shell builtin

ต่อไปนี้เป็นตัวอย่างข้อมูล bash ด้วยตนเอง:

       type [-aftpP] name [name ...]
          With no options, indicate how each name would be interpreted  if  used  as  a
          command name.  If the -t option is used, type prints a string which is one of
          alias, keyword, function, builtin,  or  file  if  name  is  an  alias,  shell
          reserved word, function, builtin, or disk file, respectively.  If the name is
          not found, then nothing is printed, and an exit status of false is  returned.
          If  the -p option is used, type either returns the name of the disk file that
          would be executed if name were specified as a command  name,  or  nothing  if
          ‘‘type  -t  name’’ would not return file.  The -P option forces a PATH search
          for each name, even if ‘‘type -t name’’ would not return file.  If a  command
          is  hashed,  -p  and -P print the hashed value, not necessarily the file that
          appears first in PATH.  If the -a option is used,  type  prints  all  of  the
          places  that  contain  an  executable  named name.  This includes aliases and
          functions, if and only if the -p option is  not  also  used.   The  table  of
          hashed  commands  is  not  consulted when using -a.  The -f option suppresses
          shell function lookup, as with the command builtin.  type returns true if any
          of the arguments are found, false if none are found.

0

อย่างที่คนอื่นพูดกันมันจะไม่ทำงานเพราะcdเป็นคำสั่ง shell builtin ไม่ใช่โปรแกรมภายนอกดังนั้นจึงไม่มีการป้อนข้อมูลมาตรฐานใด ๆ

แต่แม้ว่ามันจะทำงานได้ แต่ก็ไม่ได้ทำในสิ่งที่คุณต้องการ: ไพพ์จะวางกระบวนการใหม่และเปลี่ยนเส้นทางเอาต์พุตมาตรฐานของคำสั่งแรกไปยังอินพุตมาตรฐานของอันที่สองดังนั้นกระบวนการใหม่เท่านั้นที่จะเปลี่ยนการทำงานปัจจุบัน ไดเรกทอรี; สิ่งนี้จะไม่ส่งผลกระทบต่อกระบวนการแรก แต่อย่างใด


2
ย่อหน้าที่สองของคุณถูกต้อง แต่ย่อหน้าแรก: ทำไมคุณคิดว่าเชลล์บิวบินอินไม่มี stdin? readโดยปกติแล้วจะเป็นเชลล์ภายในหรือไม่ มันเป็นความจริงที่cdไม่สนใจ stdin แต่สิ่งนี้ไม่ได้เกิดจากการสร้างขึ้น
dubiousjim

-2

อีกตัวเลือกหนึ่งที่มี backticks ซึ่งวาง stdout $(...)ของคำสั่งหนึ่งเป็นอาร์กิวเมนต์บรรทัดคำสั่งของคำสั่งที่สองและเป็นแบบพกพามากกว่า ตัวอย่างเช่น:

cd `echo $HOME`

หรือโดยทั่วไปมากกว่า;

cd `anycommand -and whatever args`

โปรดทราบว่าการใช้ backticks ขึ้นอยู่กับเปลือกสำหรับการดำเนินการคำสั่งและแทนการส่งออกในบรรทัดคำสั่ง กระสุนส่วนใหญ่รองรับ


3
OP ระบุไว้แล้วในคำถามของเขา / เธอที่ใช้$(...)งานได้ ฉันไม่คิดว่ามันเป็นคำแนะนำที่ดีในการแนะนำ backticks แทนเนื่องจากมีกฎการอ้างอิงที่ซับซ้อนมากขึ้นและมักจะเกิดข้อผิดพลาดได้ง่าย (ดู§3.5.4 "การแทนที่คำสั่ง" ในคู่มืออ้างอิง Bash )
ruakh

$ () นั้นดีที่ได้รับการสนับสนุน แต่ backticks ได้รับการสนับสนุนอย่างกว้างขวางในเชลล์และระบบต่างๆ แต่ฉันควรใช้ถ้อยคำนี้ใหม่เป็น "ตัวเลือกอื่น"
เซทโนเบิล

กระสุนที่แตกต่างกันใช่; แต่ "ระบบ" ที่แตกต่างกันอย่างไร มีเชลล์ใดบ้างที่จะรองรับ$(...)ในระบบหนึ่ง แต่ไม่ได้อยู่ในอีกระบบหนึ่งหรือไม่?
ruakh

4
-1 มันไม่ตอบคำถามเลย
Bernhard

3
@ruakh และเซท: ทุก POSIX $(…)สนับสนุนเปลือกหอย ระบบที่ไม่มีเชลล์ POSIX (เช่นเชลล์บอร์นของแท้) จะเก่ามาก แม้แต่ระบบที่/bin/shเป็นบอร์นเชลล์และคุณต้องการพา ธ อื่นเช่น/usr/xpg4/bin/shการรับ POSIX เชลล์นั้นหาได้ยากในปัจจุบัน แนะนำ backticks ให้กับทุกคนที่ไม่ได้จัดการยูนิกซ์กล่องโบราณอย่างมืออาชีพจะทำให้พวกเขาก่อความเสียหาย
Gilles 'หยุดความชั่วร้าย'
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.