มีปัญหาเล็กน้อย
>>
ในคำสั่งแรกของคุณจะถูกตีความโดยเปลือกปัจจุบันของคุณเป็นการเปลี่ยนเส้นทางไปยังไฟล์ชื่อแท้จริง {}
เว้นแต่จะมีการเสนอราคา
*.ovpn
อาจจะขยายตัวโดยกะลากลม ๆ ก่อน find
เคยวิ่ง สิ่งนี้จะเกิดขึ้นหากคุณมีวัตถุอย่างน้อยหนึ่งรายการในไดเรกทอรีปัจจุบันที่ตรงกับรูปแบบ คุณต้องการเสนอราคานี้ เปรียบเทียบ คำถามนี้ .
คุณได้รับ Can't open echo
เพราะแน่นอนคุณกำลังบอก sh
เพื่อเปิด echo
. เพื่อรันคำสั่งที่คุณต้องการ sh -c
.
find
โดยไม่ได้ระบุเส้นทางที่ไม่ได้พกพา (เปรียบเทียบ คำถามนี้ ) ในขณะที่คุณอาจหลีกเลี่ยงสิ่งนี้ได้ฉันพูดถึงปัญหาเพื่อให้คำตอบมีประโยชน์มากขึ้นสำหรับผู้ใช้รายอื่น
นี่เป็นรุ่นปรับปรุงของคำสั่งแรกของคุณว่า ครับ ใช้งานได้ (อย่าใช้มันอ่านต่อ):
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "{}"' \;
แจ้งให้ทราบฉันต้องพูดสองครั้ง {}
ภายในเครื่องหมายคำพูดเดี่ยว เครื่องหมายคำพูดคู่เหล่านี้ "เห็น" โดย sh
และทำให้ชื่อไฟล์มีช่องว่าง ฯลฯ ทำงานเป็นเป้าหมายการเปลี่ยนเส้นทาง คุณอาจท้ายด้วยคำพูด echo "line to append" >> foo bar.ovpn
ซึ่งเทียบเท่ากับ echo "line to append" bar.ovpn >> foo
. การอ้างอิงทำให้ echo "line to append" >> "foo bar.ovpn"
แทน.
น่าเสียดายที่มีชื่อไฟล์ "
จะทำลายไวยากรณ์นี้
วิธีการผ่านที่ถูกต้อง {}
ไปยัง sh
ไม่รวมไว้ในสตริงคำสั่ง แต่จะส่งผ่านเนื้อหาเป็นอาร์กิวเมนต์แยกต่างหาก:
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$0"' {} \;
$0
ภายในสตริงคำสั่งขยายไปยังอาร์กิวเมนต์แรกของเรา sh
ได้รับหลังจาก -c '…'
. แม้แต่ตอนนี้ "
ในชื่อไฟล์จะไม่ทำลายไวยากรณ์
โดยปกติ (เช่นในสคริปต์) เพื่ออ้างถึงอาร์กิวเมนต์แรกที่คุณใช้ $1
. นี่คือเหตุผลที่ผู้ใช้บางคนต้องการใช้อาร์กิวเมนต์ดัมมี่เป็น $0
, อย่างนี้:
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' dummy {} \;
ถ้ามันเป็นสคริปต์ $0
จะขยายไปยังชื่อของมัน นั่นเป็นเหตุผลที่ไม่ใช่เรื่องแปลกที่จะเห็นสิ่งนี้ dummy
เป็นจริง sh
(หรือ bash
หากมีสายเข้า bash -c …
ฯลฯ ):
find . -name '*.ovpn' -exec sh -c 'echo "line to append" >> "$1"' sh {} \;
แต่เดี๋ยวก่อน! find
โทรแยกต่างหาก sh
สำหรับไฟล์ทุกไฟล์ ฉันไม่ได้คาดหวังว่าคุณจะมีเป็นพัน .ovpn
ไฟล์ แต่โดยทั่วไปคุณอาจต้องการประมวลผลไฟล์จำนวนมากโดยไม่ต้องวางไข่กระบวนการที่ไม่จำเป็น เราสามารถปรับวิธีให้เหมาะสมด้วย tee -a
ที่สามารถเขียนไปยังหลาย ๆ ไฟล์เป็นกระบวนการเดียว:
find . -name '*.ovpn' -exec sh -c 'echo "line to append" | tee -a "$@" >/dev/null' sh {} +
แจ้งให้ทราบ {} +
สิ่งนี้จะผ่านหลายเส้นทางพร้อมกัน ภายในคำสั่งดำเนินการโดย sh -c
เราดึงมันมาด้วย "$@"
ซึ่งขยายไปถึง "$1" "$2" "$3" …
. ในกรณีนี้อาร์กิวเมนต์ดัมมีที่ใส่ (ไม่ได้ใช้) $0
คือต้อง
โดยทั่วไปแล้วยังมีปัญหานี้: ทำไม printf
ดีกว่า echo
? อย่างไรก็ตามในกรณีนี้คุณกำลังใช้ echo
ไม่มีตัวเลือกและสตริงที่ได้รับเป็นแบบคงที่ดังนั้นควรปรับ