จะแทนที่ช่องว่างในชื่อไฟล์ทั้งหมดด้วยเครื่องหมายขีดล่างใน Linux โดยใช้เชลล์สคริปต์ได้อย่างไร


17

ฉันลองต่อไปนี้เชลล์สคริปต์ซึ่งควรแทนที่ช่องว่างจากชื่อไฟล์ xml ทั้งหมด

for xml_file in $(find $1 -name "* .xml" -type f);
do
 echo "removing spaces from XML file:" $xml_file
 mv "$xml_file" "${xml_file// /_}";
done

สมมติว่าฉันมีไฟล์ xml ที่มีชื่อxy z.xmlจากนั้นจะให้:

removing spaces from XML file: /home/krishna/test/xy
mv: cannot stat `/home/krishna/test/xy': No such file or directory
removing spaces from XML file: .xml
mv: cannot stat `z.xml': No such file or directory

คำตอบ:


29

ใช้สิ่งนี้กับbash:

find $1 -name "* *.xml" -type f -print0 | \
  while read -d $'\0' f; do mv -v "$f" "${f// /_}"; done

findจะค้นหาไฟล์ที่มีช่องว่างในชื่อ ชื่อไฟล์จะถูกพิมพ์ด้วย nullbyte ( -print0) เป็นตัวคั่นเพื่อจัดการกับชื่อไฟล์พิเศษ จากนั้นreadbuiltin จะอ่านชื่อไฟล์ที่คั่นด้วย nullbyte และสุดท้ายmvแทนที่ช่องว่างด้วยขีดล่าง

แก้ไข:หากคุณต้องการลบช่องว่างในไดเรกทอรีด้วยมันซับซ้อนกว่าเล็กน้อย ไดเรกทอรีถูกเปลี่ยนชื่อแล้วไม่สามารถเข้าถึงได้โดยชื่อfindค้นหา ลองสิ่งนี้:

find -name "* *" -print0 | sort -rz | \
  while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done

sort -rzฝืนคำสั่งไฟล์เพื่อให้ไฟล์ที่ลึกที่สุดในโฟลเดอร์เป็นครั้งแรกที่จะย้ายและโฟลเดอร์ตัวเองจะเป็นคนสุดท้าย ดังนั้นจึงไม่เคยเปลี่ยนชื่อโฟลเดอร์ก่อนที่ไฟล์และโฟลเดอร์ทั้งหมดจะถูกเปลี่ยนชื่อภายใน mvคำสั่งในวงเป็นบิตเปลี่ยนแปลงมากเกินไป ในชื่อเป้าหมายเราจะลบช่องว่างในชื่อไฟล์พื้นฐานมิฉะนั้นจะไม่สามารถเข้าถึงได้


ฉันกำลังพยายามแทนที่ช่องว่างด้วยการขีดเส้นใต้ในไดเรกทอรีทั้งหมด แต่มันให้ข้อผิดพลาดเพราะหลังจากเปลี่ยนชื่อแล้วไดเรกทอรีนั้นไม่สามารถเข้าถึงได้
กฤษณะ

@krishna ฉันเพิ่มการแก้ไขในคำตอบของฉัน
ความวุ่นวาย

1
@ chaos ว้าวแค่วิ่งสองคนนี้ทั้งสองระบบและมันทำงานได้อย่างมีเสน่ห์มีไฟล์ไม่กี่ไฟล์และ dirs ไม่ผ่าน แต่มันมีเพียงไม่กี่
บางอย่างบางอย่าง

บน macOS เราจำเป็นต้องระบุไดเรกทอรีในคำสั่ง find ก่อนตัวเลือก -name find . -name "* *" -print0 | sort -rz | \ while read -d $'\0' f; do mv -v "$f" "$(dirname "$f")/$(basename "${f// /_}")"; done
Laszlo Pinter

17
  1. การใช้ rename

    find . -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;

    หรือกับ $1

    find "$1" -type f -name "* *.xml" -exec rename "s/\s/_/g" {} \;
  2. การใช้ mv

    find . -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

    หรือกับ $1

    find "$1" -type f -name "* *.xml" -exec bash -c 'mv "$0" "${0// /_}"' {} \;

ฉันไม่รู้ว่าทำไม แต่คำสั่งที่คุณให้ไม่ทำงานสำหรับฉัน มันไม่ได้แสดงข้อผิดพลาดและเอาท์พุท
กฤษณะ

@krishna แก้ไขแล้วขอโทษ
AB

1
การเปลี่ยนชื่อทำงานให้ฉัน Fistbump!
Brian Piercy

1

นี่เป็นวิธีที่ฉันพบขณะเผชิญปัญหาเดียวกัน:

for f in *; do mv "$f" `echo $f | tr ' ' '_'`; done

ฉันกำลังเขียนไฟล์สคริปต์ทุบตีเพื่ออัปเดตใบรับรอง SSL ของฉันโดยอัตโนมัติ


1

การใช้rename:

rename 's/\s/_/g' ./*.xml

ไม่ต้องการ find :)


1
เพิ่ม g ต่อท้ายลงใน regex และทำงานได้อย่างสมบูรณ์ 's / \ s / _ / g'
jbrahy

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