มีปัญหาเล็กน้อย
>> ในคำสั่งแรกของคุณจะถูกตีความโดยเปลือกปัจจุบันของคุณเป็นการเปลี่ยนเส้นทางไปยังไฟล์ชื่อแท้จริง {}เว้นแต่จะมีการเสนอราคา
*.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 ไม่มีตัวเลือกและสตริงที่ได้รับเป็นแบบคงที่ดังนั้นควรปรับ