ทำไมคำสั่ง xargs นี้ไม่ทำงาน


14

ฉันต้องการลบส่วนขยาย. sh ทั้งหมดเพื่อทำสิ่งนี้:

ls *.sh | xargs -I {} mv {} `basename {} .sh`

อย่างไรก็ตามมันไม่ทำงานมันจะทำงานเหมือนbasenameส่งคืนชื่อไฟล์ที่ไม่เปลี่ยนแปลง

ทำไมมันเป็นเช่นนั้น

ตัวอย่างเช่นงานนี้:

ls *.sh | xargs -I {} echo `basename {}.jpg .jpg`;

แก้ไข :

วิธีแก้ไข: อัญประกาศเดี่ยวป้องกัน`basename ...`การประเมินผลโดยเชลล์ก่อนที่คำสั่งจะรัน

ls *.sh | xargs -I {}  sh -c 'mv {} `basename {} .sh`'

คำตอบ:


12

เนื่องจากคำสั่ง basename รันก่อนที่จะรันไปป์ไลน์ ในการทำให้งานนี้คุณต้องการ xargs เพื่อเรียกใช้งาน basename และคุณสามารถทำได้sh -cเช่น:

ls *.sh | xargs -L1 sh -c 'basename $1 .sh' dummy

หมายเหตุ:

  • หากคุณไม่บอกxargsตำแหน่งที่จะใส่ชื่อไฟล์พวกเขาจะถูกเพิ่มที่ส่วนท้ายของบรรทัดคำสั่ง
  • คุณควรใช้-L1สวิตช์หรือสิ่งที่เทียบเท่าดังนั้นxargsส่งผ่านหนึ่งอาร์กิวเมนต์shเท่านั้น
  • โดยใช้การส่งออกของlsอาจจะมีผลกระทบที่ไม่พึงประสงค์

แก้ไข

ลบตัวเลือกที่เลิกใช้แล้วขอบคุณ TechZilla


3
จุดแรกของคุณไม่ถูกต้องเว้นแต่คุณจะหมายความว่าเป็นค่าเริ่มต้นตาม-iตัวเลือก แต่ตัวเลือก 'แบบคลาสสิก' ได้ถูกคัดค้าน ยกตัวอย่างเช่นการใช้เพียงหนึ่งตัวเลือก / บรรทัดใหม่หน้าคน POSIX -L1แนะนำ หากต้องการเรียกพฤติกรรมเก่าของ-iหน้าแนะนำ-I'{}'ตัวเลือก
JM Becker

ดังนั้นมันเกี่ยวกับสัญลักษณ์ '' แทน "" ฉันเดาว่าจะป้องกันการประเมินเชลล์ของ `` ดูการแก้ไขของฉัน
majkinetor

@TechZilla: ขอบคุณสำหรับการแก้ไข @ majkinetor: ใช่และไม่ใช่คุณต้องชะลอการประเมินผล แต่ฉันไม่คิดว่าคุณสามารถใช้ backticks (`) ได้
Thor

1
@majkinetor: อ่าฉันเห็นแล้วว่าคุณหมายถึงอะไร หากต้องการเปลี่ยนชื่อไฟล์ในลักษณะนี้ฉันควรจะใช้renameเช่น: rename 's/\.sh//' *.sh. ลองก่อนด้วย dry-run ( -n)
Thor

1
@ majkinetor: renameทำงานได้ดีและค่อนข้างง่าย แต่จำไว้ว่ามันมีการกระจายเฉพาะ การแจกแจงแบบอิง RHEL และ Debian จัดเตรียมrenameคำสั่งที่แตกต่างกันดังนั้นจึงต้องระลึกไว้เสมอเมื่อสร้างสคริปต์ครอส - distro
JM Becker

4

ฉันไม่แน่ใจเกี่ยวกับคำถามของคุณคุณกำลังถามว่าทำไมบรรทัดแรกของคุณใช้งานไม่ได้? หรือคุณกำลังมองหาวิธีที่เหมาะสมในการเปลี่ยนชื่อไฟล์. sh ทั้งหมดหรือไม่

สมมติว่ามันเป็นวิธีการที่สะอาด, xargsฉันชอบที่จะเตรียมความพร้อมตัวเลือกคำสั่งก่อน สำหรับการลบนามสกุลไฟล์. sh ฉันมักจะพิจารณาวิธีนี้

 find -maxdepth 1 -type f -iname '*.sh'  | sed 'p;s_.sh$__' | xargs -L2 mv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.