แทนที่จุดในชื่อไฟล์ด้วยขีดล่างยกเว้นนามสกุล


9

มีคนแนะนำวิธีเปลี่ยนชื่อไฟล์ได้ไหม:

head.body.date.txt

ถึง:

head_body_date.txt

มีคำสั่งบรรทัดเดียวในการเปลี่ยนชื่อในUnixหรือไม่?


9
คุณคิดว่า.tar.gzมันเป็นส่วนเสริมหรือไม่? นอกจากนี้ยินดีต้อนรับสู่ U&L!
EKons

2
คุณหมายถึง Unix จริงๆเมื่อเทียบกับ Linux หรือไม่? อันไหน Unix?
terdon

1
mv head.body.date.txt head_body_date.txtคำตอบที่ชัดเจนคือ หากคุณมีข้อ จำกัด อื่น ๆ หรือตัวอย่างจริงโปรดอัปเดตคำถามของคุณด้วยสิ่งเหล่านี้ ตามที่อธิบายไว้ในตอนนี้มันไม่ชัดเจนว่าคำถามนั้นอ้างถึงไฟล์ที่มีชื่อชัดเจนหรือไม่ซึ่งเป็นไดเรกทอรีเดียวที่ไฟล์ทั้งหมดมีรูปแบบเฉพาะหรือถ้าคุณต้องการค้นหาลำดับชั้นไดเรกทอรีสำหรับชื่อเฉพาะและเปลี่ยนชื่อเหล่านี้
Kusalananda

คำตอบ:


9

ทำซ้ำชื่อไฟล์และใช้การขยายพารามิเตอร์สำหรับการแปลง:

for f in *.*.*.txt; do i="${f%.txt}"; echo mv -i -- "$f" "${i//./_}.txt"; done

รูปแบบการขยายพารามิเตอร์${f//./_}แทนที่.s ทั้งหมดด้วย_s ในชื่อไฟล์ ( $f)

ด้านบนจะทำการแบบแห้งเพื่อให้การเปลี่ยนชื่อจริงเกิดขึ้นให้ลบecho:

for f in *.*.*.txt; do i="${f%.txt}"; mv -i -- "$f" "${i//./_}.txt"; done

หากคุณต้องการจัดการกับส่วนขยายใด ๆ ไม่ใช่เพียง.txt:

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     echo mv -i -- "$f" "${pre//./_}.${suf}"; done

หลังจากตรวจสอบการลบechoสำหรับการดำเนินการจริง:

for f in *.*.*.*; do pre="${f%.*}"; suf="${f##*.}"; \
                     mv -i -- "$f" "${pre//./_}.${suf}"; done

ทั่วไปสำหรับจำนวนจุดโดยพลการอย่างน้อยหนึ่ง:

for f in *.*; do pre="${f%.*}"; suf="${f##*.}"; \
                 mv -i -- "$f" "${pre//./_}.${suf}"; done

มีวิธีการทั่วไปหรือไม่ถ้ามีจำนวนจุดโดยพลการ?
Ciprian Tomoiagă

1
@CiprianTomoiaga ทำ:for f in *.*; do ...; done
heemayl

ฉันอาจแนะนำให้วาง*.*รูปแบบตรงในตัวอย่างเนื่องจากตอนนี้รหัสดูเหมือนว่าจะทำงานเฉพาะกับจำนวนจุดคงที่
ilkkachu

@ilkkachu ยุติธรรมพอแก้ไข
heemayl

ขอบคุณ heemay มากมันใช้งานได้สำหรับฉัน และการเรียนรู้บางอย่าง!
SG

4

ด้วยperlตามrename

$ rename -n 's/\.[^.]+$(*SKIP)(*F)|\./_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)
  • \.[^.]+$(*SKIP)(*F) ข้ามรูปแบบนี้และค้นหาการจับคู่ทางเลือก
  • |\./_/gแทนที่ทั้งหมด.ด้วย_

หรือใช้ lookahead เชิงลบ

$ rename -n 's/\.(?![^.]+$)/_/g' head.body.date.txt 
rename(head.body.date.txt, head_body_date.txt)

เมื่อไม่เป็นไรให้ลบ-nตัวเลือก


3
rename 's/\.(?=[^.]*\.)/_/g' *.txt

ใช้ regex ทดแทนเพื่อค้นหาทุก แต่อินสแตนซ์สุดท้ายของ.ในชื่อไฟล์ (ไม่ใช่จับ lookahead) _และแทนที่ด้วย พูดถึง*.*ถ้าคุณชอบ

( renameดูเหมือนว่าเวอร์ชั่นเฉพาะของนี้จะติดตั้งผ่านutil-linux) ฉันกำลังใช้Ubuntu 12.04(ใช่เครื่องล้าสมัยอย่างรุนแรง)


2

bash:

old=head.body.date.txt oldb=${old%.*} olde=${old##*.} ; \
mv -- "$old" "${oldb//./_}.${olde}"

(1) คุณควรจะใช้mv --เพื่อป้องกันการ“เก่า” -ชื่อไฟล์ที่ขึ้นต้นด้วย (2) คุณควรใส่$oldเครื่องหมายคำพูด ( "$old") เพื่อป้องกันชื่อไฟล์ "เก่า" ที่มีช่องว่างหรือตัวอักษรที่พิเศษสำหรับเชลล์ (เช่น*และ?) (3) คำตอบของคุณล้มเหลวในกรณีที่ค่อนข้างพยาธิวิทยาที่ขยายมีขีด: ได้รับการเปลี่ยนชื่อเป็นhead.body.date.t_xt head_body_date_t.xt
สกอตต์

@Scott ขอบคุณ ตอนนี้โค้ดได้รับการปรับแต่งตามรายการทั้งสามที่กล่าวถึง
agc

1

การใช้mv, sedและrevในหนึ่งบรรทัด:

mv "head.body.date.txt" "$(echo head.body.date.txt | rev | sed 's/\./_/2g' | rev)"

หากคุณต้องการที่จะนำไปใช้กับtxtไฟล์ทั้งหมดในตัวแทนปัจจุบันการใช้ globs ดูเหมือนจะยุ่งยากเนื่องจากวิธีการmvทำงาน แต่คุณสามารถทำforลูปในหนึ่งซับ:

for file in *.txt; do mv "$file" "$(echo $file | rev | sed 's/\./_/2g' | rev)"; done

อีกเล็กน้อย แต่คุณสามารถจับคู่หลายรูปแบบในวงของคุณ!


2
(1) Arrghhh! อย่าทำ$(ls …); for file in *.txtเพียงแค่ทำ (2) mv "$file" "$(…)"คุณควรใช้คำพูดมากขึ้น:
สกอตต์

ขอขอบคุณสก็อตต์บันทึกและแก้ไขอย่างถูกต้อง! ฉันยังเป็นเด็กอยู่ในเปลือกโปรดเป็นคนอ่อนโยน;)
Valentin B.

ในการเข้าใจย้อนหลังการใช้renameเหมือนคนอื่น ๆ หลายคนได้แนะนำในคำตอบของพวกเขาเสียงจะง่ายกว่าแม้ว่า ...
Valentin B.

-1
 mv head.body.date.txt head_body_date.txt

มันง่ายเหมือนไฟล์เดียวในแต่ละครั้ง คุณไม่ได้ระบุว่าคุณต้องการให้ทำซ้ำในไดเรกทอรีหรือไดเรกทอรีทั้งหมดเลยเพื่อให้เป็นวิธีแก้ปัญหาที่สะดวกและรวดเร็วที่สุด

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