ทำไมฉันต้องใช้ cd“ $ @” แทน cd“ $ 1” เมื่อเขียน wrapper สำหรับ cd?


25

ที่อื่นฉันได้เห็นฟังก์ชั่น cd ดังนี้

cd()
{
 builtin cd "$@"
}

ทำไมมันแนะนำให้ใช้$@แทน$1?

ฉันสร้างไดเรกทอรีทดสอบ "r st" และเรียกว่าสคริปต์ที่มีฟังก์ชั่นนี้และทำงานได้ทั้งสองวิธี

$ . cdtest.sh "r st"

แต่ $ . cdtest.sh r stล้มเหลวไม่ว่าฉันจะใช้"$@"หรือ"$1"


1
cd "$*"ยังทำงานไม่ถูกต้องโดยมี arg มากกว่า 1 อัน
GoFundMonica - codidact.org

คำตอบ:


57

เพราะตามbash(1), cdใช้อาร์กิวเมนต์

   cd [-L|[-P [-e]] [-@]] [dir]
          Change  the  current  directory to dir.  if dir is not supplied,
          ...

ดังนั้นไดเรกทอรีจริงอาจไม่อยู่ใน$1ที่อาจเป็นตัวเลือกเช่น-Lหรือธงอื่น

มันเลวร้ายขนาดไหน?

$ cd -L /var/tmp
$ pwd
/var/tmp
$ cd() { builtin cd "$1"; }
$ cd -L /var/tmp
$ pwd
/home/jhqdoe
$ 

สิ่งต่าง ๆ อาจผิดเพี้ยนไปมากถ้าคุณไม่ได้ใช้cd "$1"...


19

การใช้"$@"จะส่งผ่านอาร์กิวเมนต์ทั้งหมดไปยังcdตำแหน่งที่$1จะส่งผ่านอาร์กิวเมนต์แรกเท่านั้น

ในตัวอย่างของคุณ

$ . cdtest.sh "r st"

ใช้งานได้ตามที่คุณส่งผ่านในอาร์กิวเมนต์เดียวเสมอ แต่ถ้าคุณผ่านการตั้งค่าสถานะเช่นกัน

$ . cdtest.sh -L "r st"

จากนั้น"$@"จะดำเนินการอย่างถูกต้องเท่านั้นซึ่ง"$1"จะขยายไปที่cd -Lสูญเสียไดเรกทอรีทั้งหมด

อย่างไรก็ตาม

$ . cdtest.sh r st

ล้มเหลวในทั้งสองกรณีขณะที่คุณส่งพารามิเตอร์สองตัวไปยัง cd rและstไม่เป็นวิธีที่ถูกต้องในการดำเนินการ cd พารามิเตอร์จะถูกคั่นด้วยช่องว่างซึ่งจะต้องยกมา (เช่นในตัวอย่างแรกของคุณ) หรือหนี ( r\ st) จะถือว่าเป็นหนึ่งอาร์กิวเมนต์

ในกรณีของ cd อย่างไรก็ตามมันเป็นเรื่องผิดปกติมากที่จะส่งผ่านค่าสถานะและคุณไม่สามารถส่งผ่านไปยังหลาย ๆ ไดเรกทอรีได้ดังนั้นคุณจะไม่เห็นความแตกต่างในการใช้งานจริง"$1"หรือ"$@"ซีดี แต่สำหรับคำสั่งอื่นคุณจะสังเกตเห็นความแตกต่างดังนั้นจึงควรใช้"$@"เมื่อคุณต้องการสร้างฟังก์ชั่น wrapper หรือสคริปต์เช่นนี้


14

นอกจากนี้ยังมีกรณีเมื่อไม่มีข้อโต้แย้ง:

$ cd /tmp; cd; pwd
/home/muru
$ cd_func() { builtin cd "$1"; }
$ cd_func /tmp; cd_func; pwd
/tmp

cdไม่มีข้อโต้แย้งใด ๆ เปลี่ยนเป็นไดเรกทอรีบ้าน โดยไม่มีข้อโต้แย้งใด ๆ"$@"ขยายไปที่ไม่มีอะไร แต่"$1"ขยายไปยังสตริงที่ว่างเปล่า สิ่งเหล่านี้แตกต่าง:

$ args() { for i in "$@"; do echo "|$i|"; done; }
$ args
$ args ""
||

ค่อนข้างไม่เกี่ยวข้อง แต่: ในที่สุดฉันก็เข้าใจว่าทำไมการโต้เถียงแบบโมฆะถึงcdเป็นสิ่งที่ดี มันทำให้เกิดข้อผิดพลาดแทนการเปลี่ยนเป็นโฮมไดเร็กตอรี่ ด้วยบางคำสั่งอื่น ๆ ที่โดดเด่นrsyncอาร์กิวเมนต์แรกเป็นโมฆะทำให้เกิดพฤติกรรมที่ไม่คาดคิด (รวมถึงไดเรกทอรีปัจจุบันในแหล่งที่มาของการถ่ายโอน)
โจ

4

อาร์กิวเมนต์ของสคริปต์ทุบตีเป็นตัวคั่นช่องว่าง $ 1 คืออาร์กิวเมนต์แรก ในตัวอย่างของคุณ ...

ในตัวอย่างที่ 1 $ 1 คือสตริง "r st" ... ในตัวอย่างที่สอง $ 1 คือสตริงอักขระหนึ่งตัว 'r' ...

$ @ คือข้อโต้แย้งทั้งหมด

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