ต่อท้ายบรรทัดใหม่ไปยังหลายไฟล์


1

ฉันพยายามต่อท้ายบรรทัดใหม่ไปยังหลายไฟล์ด้วยคำสั่งต่อไปนี้:

find -name *.ovpn -exec sh echo "line to append" >> {} \;

ก่อนที่จะทำสิ่งนี้ฉันได้รับคำสั่งต่าง ๆ เพื่อให้แน่ใจว่ามันจะเป็นไปตามที่ฉันคาดไว้:

find -name *.ovpn -exec sh echo "hello" \;

แต่ทั้งหมดนี้จะพิมพ์ออกมา "sh: 0: ไม่สามารถเปิดเสียงสะท้อน" สำหรับทุกไฟล์ที่พบ

คำตอบ:


3

มีปัญหาเล็กน้อย

>> ในคำสั่งแรกของคุณจะถูกตีความโดยเปลือกปัจจุบันของคุณเป็นการเปลี่ยนเส้นทางไปยังไฟล์ชื่อแท้จริง {}เว้นแต่จะมีการเสนอราคา

*.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 ไม่มีตัวเลือกและสตริงที่ได้รับเป็นแบบคงที่ดังนั้นควรปรับ

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