ฉันจะเปลี่ยนชื่อโฟลเดอร์และไฟล์ทั้งหมดเป็นตัวพิมพ์เล็กบน Linux ได้อย่างไร


179

ฉันต้องเปลี่ยนชื่อโฟลเดอร์ทรีที่สมบูรณ์แบบวนซ้ำเพื่อให้ไม่มีตัวอักษรตัวใหญ่ปรากฏขึ้นที่ใดก็ได้ (เป็นซอร์สโค้ด C ++ แต่ไม่ควรสำคัญ)

คะแนนโบนัสสำหรับการละเว้นไฟล์ / โฟลเดอร์สำหรับควบคุมเวอร์ชัน CVS และเวอร์ชั่นโค่นล้ม วิธีที่แนะนำคือเชลล์สคริปต์เนื่องจากเชลล์ควรมีอยู่ในกล่อง Linux ใด ๆ

มีข้อโต้แย้งที่ถูกต้องเกี่ยวกับรายละเอียดของการเปลี่ยนชื่อไฟล์

  1. ฉันคิดว่าไฟล์ที่มีชื่อตัวพิมพ์เล็กเดียวกันควรเขียนทับ มันเป็นปัญหาของผู้ใช้ เมื่อเช็กเอาต์ในระบบไฟล์ที่คำนึงถึงขนาดตัวพิมพ์มันก็จะเขียนทับระบบแรกด้วยอันหลังด้วย

  2. ฉันจะพิจารณาตัวอักษร AZ และแปลงให้เป็น az ทุกอย่างอื่นก็แค่เรียกหาปัญหา (อย่างน้อยก็มี source code)

  3. สคริปต์จำเป็นต้องมีการรัน build บนระบบ Linux ดังนั้นฉันคิดว่าควรละเว้นการเปลี่ยนแปลงไฟล์ควบคุมเวอร์ชัน CVS หรือเวอร์ชัน Subversion หลังจากทั้งหมดมันเป็นเพียงการตรวจสอบรอยขีดข่วน บางที "ส่งออก" อาจเหมาะสมกว่า


โพสต์ก่อนหน้านี้จะทำงานได้อย่างสมบูรณ์นอกกรอบหรือมีการปรับเปลี่ยนเล็กน้อยสำหรับกรณีง่าย ๆ แต่มีบางสถานการณ์ที่คุณอาจต้องคำนึงถึงก่อนที่จะทำการเปลี่ยนชื่อแบทช์: 1. จะเกิดอะไรขึ้นถ้าคุณมีสองชื่อขึ้นไป ในระดับเดียวกันในลำดับชั้นของเส้นทางที่แตกต่างกันโดยเฉพาะกรณีเช่นABCdef, abcDEFและaBcDeF? สคริปต์การเปลี่ยนชื่อควรยกเลิกหรือเพียงแค่เตือนและดำเนินการต่อหรือไม่ 2. คุณจะกำหนดตัวพิมพ์เล็กสำหรับชื่อที่ไม่ใช่ US-ASCII ได้อย่างไร หากมีชื่อดังกล่าวอยู่ควรมีการตรวจสอบและการยกเว้นรหัสผ่านอย่างใดอย่างหนึ่งก่อนหรือไม่ 3. หากคุณใช้งานการเปลี่ยนชื่อ
Mihai Limbășan

คำตอบ:


179

เวอร์ชันที่กระชับโดยใช้"rename"คำสั่ง:

find my_root_dir -depth -exec rename 's/(.*)\/([^\/]*)/$1\/\L$2/' {} \;

วิธีนี้จะช่วยหลีกเลี่ยงปัญหากับไดเรกทอรีที่ถูกเปลี่ยนชื่อก่อนไฟล์และพยายามย้ายไฟล์ไปยังไดเรกทอรีที่ไม่มีอยู่ (เช่น"A/A"เข้าไป"a/a")

"rename"หรือรุ่นที่ละเอียดมากขึ้นโดยไม่ต้องใช้

for SRC in `find my_root_dir -depth`
do
    DST=`dirname "${SRC}"`/`basename "${SRC}" | tr '[A-Z]' '[a-z]'`
    if [ "${SRC}" != "${DST}" ]
    then
        [ ! -e "${DST}" ] && mv -T "${SRC}" "${DST}" || echo "${SRC} was not renamed"
    fi
done

PS

หลังให้ความยืดหยุ่นมากขึ้นด้วยคำสั่งย้าย (ตัวอย่างเช่น"svn mv")


36
การใช้การเปลี่ยนชื่อสามารถทำได้ด้วยวิธีนี้เช่นกันการเปลี่ยนชื่อ 'y / AZ / az /' *
Tzury Bar Yochay

3
ระวังทั้งสองเวอร์ชันจะไม่ทำงานบนระบบไฟล์ที่ไม่สนใจขนาดตัวพิมพ์ ในกรณีของฉันฉันแทนที่thenสาย -enclosed (mv "${SRC}" "${DST}.renametmp" && mv "${DST}.renametmp" "${DST}") || echo "${SRC} was not renamed"โดย
Lloeki

6
วิธีที่สองทำงานไม่ถูกต้องสำหรับฉันกับไฟล์ที่มีช่องว่าง (บริบท: linux, bash)
สลัว

4
การใช้การเปลี่ยนชื่อรุ่นล่าสุดไม่จำเป็นต้องใช้ regex find my_root_dir -depth -exec rename -c {} \;คำสั่งเต็มกลายเป็น เพิ่ม -f เพื่อเปลี่ยนชื่อหากคุณใช้ระบบไฟล์แบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ (เช่น Mac)
Javache

คนที่สองทำงานให้ฉันบน Solaris โดยการเอา-Tจากmvคำสั่ง
แฮม

261

ยังเล็กฉันชอบ:

rename 'y/A-Z/a-z/' *

ในกรณีที่ระบบไฟล์ไม่คำนึงถึงขนาดตัวพิมพ์เช่นHFS +ของ OS X คุณจะต้องเพิ่มการ-fตั้งค่าสถานะ:

rename -f 'y/A-Z/a-z/' *

3
linux.icydog.net/rename.php :The renaming utility that comes by default with Ubuntu is a Perl program sometimes called prename
sleepsort

1
ขอบคุณฉันใช้มันด้วยวิธีนี้ $ find | xargs เปลี่ยนชื่อ 'y / AZ / az /' *
Rashi

5
สิ่งนี้ถือว่าคุณมีการเปลี่ยนชื่อ perls ซึ่งไม่ใช่กรณีนี้เสมอไป เช่นในการเปลี่ยนชื่อเดเบียนของฉันแตกต่างอย่างสิ้นเชิง
Krzysztof Krasoń

10
บน Arch โปรแกรมถูกเรียกใช้perl-rename(และจัดทำโดยแพ็คเกจที่มีชื่อเดียวกัน)
jaymmer - Reinstate Monica

3
สิ่งนี้ไม่ตอบปัญหาที่ได้รับเนื่องจาก "การเปลี่ยนชื่อ" ไม่ได้เรียกซ้ำ
Cybolic

89
for f in `find`; do mv -v "$f" "`echo $f | tr '[A-Z]' '[a-z]'`"; done

โปรดทำ "mkdir -p A / B / C" ก่อนที่จะเรียกใช้สคริปต์ของคุณ
tzot

2
"find" ควรถูกแทนที่ด้วยคำสั่งใด ๆ ที่คุณใช้เพื่อรับรายการไฟล์ที่คุณต้องการเปลี่ยนชื่อ; ตัวอย่างเช่น "ls *. {C, CPP, H}"
JPaget

2
ไม่ทำงานบน OS X findเพียงแค่พิมพ์ข้อมูลการใช้งานสำหรับ find .ดูเหมือนว่าจะแก้ไขปัญหานี้
emlai

3
เวอร์ชั่น "รวม" จากความคิดเห็นทั้งหมด (ไม่สามารถแก้ไขคำตอบได้อีกต่อไป):for f in `find .`; do mv -v "$f" "`echo $f | tr '[A-Z]' '[a-z]'`"; done
romaricdrigon

1
ใครสามารถอธิบายให้ฉันฟังได้ว่าทำไมสิ่งนี้ถึงควรทำงานตั้งแต่แรก? หากพบ. /FOO และ ./FOO/BAR ก่อนอื่นให้เปลี่ยนชื่อ. /FOO เป็น ./foo หลังจากนั้นไม่สามารถหา. /FOO/BAR อีกต่อไป ป้อนคำตอบของฉันเองด้านล่างซึ่งควรแก้ไข
oisyn

80

เพียงลองทำสิ่งต่อไปนี้หากคุณไม่ต้องการประสิทธิภาพ

zip -r foo.zip foo/*
unzip -LL foo.zip

13
ว้าวนั่นเป็นวิธีที่ไม่มีประสิทธิภาพเลยทีเดียว
Artjom B.

28
สมมติว่าประสิทธิภาพการคำนวณโดยทั่วไปแล้วไม่ใช่เรื่องที่น่ากังวลเมื่อคุณพบว่าตัวเองต้องการเปลี่ยนชื่อไฟล์ในไดเรกทอรี ... ฉันคิดว่านี่น่าจะเป็นทางออกที่ง่ายที่สุดในเธรดนี้ จริงๆแล้วสิ่งเล็ก ๆ น้อย ๆ นี้ไม่ควรซับซ้อนเหมือนคำตอบที่ได้รับการยอมรับและการแก้ปัญหานี้มีความเหมาะสมกับปริมาณความคิดที่ฉันต้องการลงทุนในการดำเนินการเช่นนี้ +1000
Peter M. Elias

27
คุณสามารถเพิ่มความเร็วขึ้นกับ-0(ว่า 'ศูนย์' ไม่มีการบีบอัด) zip -0 -r foo.zip foo/สวิทช์
Johnny Baloney

3
ฉันต้องเปลี่ยนชื่อไฟล์มากกว่า 50,000 รายการในโครงสร้างไดเรกทอรีที่แตกต่างกัน คำตอบเดิมที่ได้รับการยอมรับนั้นแทบจะไม่ได้รับผลงาน 10% ในเวลา 2 นาทีที่การ-0บีบอัดนี้เกือบจะทันที
Peon

2
มันไม่ได้มีประสิทธิภาพแค่เพียงอย่างเดียว อันนี้เป็นไปไม่ได้ถ้ามีพื้นที่ว่างไม่เพียงพอสำหรับการเก็บถาวรชั่วคราว
Victor Yarema

20

ผู้ชายคุณผู้ชาย / gals ชอบที่จะซับซ้อนกว่าสิ่งต่าง ๆ ... ใช้:

rename 'y/A-Z/a-z/' *

2
สิ่งนี้ไม่ทำงานมันบอกว่ามีไฟล์ที่มีชื่อต่ำกว่าอยู่แล้ว
kirhgoff

@kirhgoff ผมเคยเห็นที่เกิดขึ้นกับม้า NFS - ทำตามคำแนะนำที่นี่
joebeeson

เราจะเปลี่ยนชื่อในระบบไฟล์แบบตรงตามตัวพิมพ์เล็ก - ใหญ่ได้อย่างไร? rename 'y/a-z/A-Z/' /tmp/*.jpg-> Can't rename /tmp/*.jpg /TMP/*.JPG: No such file or directoryคือพยายามเปลี่ยนชื่อพา ธ ทั้งหมดแทนที่จะเป็นไฟล์
Pablo A

14

คำตอบส่วนใหญ่ข้างต้นมีอันตรายเพราะไม่เกี่ยวข้องกับชื่อที่มีอักขระแปลก ๆ เดิมพันที่ปลอดภัยที่สุดของคุณสำหรับชนิดของสิ่งนี้คือการใช้findของ-print0ตัวเลือกซึ่งจะยุติชื่อไฟล์กับ ASCII NUL แทน \ n

นี่คือสคริปต์ซึ่งแก้ไขไฟล์เท่านั้นและไม่ใช่ชื่อไดเรกทอรีเพื่อไม่ให้สับสนfind:

find .  -type f -print0 | xargs -0n 1 bash -c \
's=$(dirname "$0")/$(basename "$0");
d=$(dirname "$0")/$(basename "$0"|tr "[A-Z]" "[a-z]"); mv -f "$s" "$d"'

ฉันทดสอบแล้วและใช้งานได้กับชื่อไฟล์ที่มีช่องว่างคำพูดทุกชนิด ฯลฯ นี่เป็นสิ่งสำคัญเพราะถ้าคุณเรียกใช้ในฐานะ root หนึ่งในสคริปต์อื่น ๆ เหล่านั้นบนต้นไม้ที่มีไฟล์ที่สร้างโดย

touch \;\ echo\ hacker::0:0:hacker:\$\'\057\'root:\$\'\057\'bin\$\'\057\'bash

... ลองเดาดูสิ ...


มันจะง่ายมากขึ้นเพื่อใช้แทนrename mv
Victor Yarema

14

ใช้งานได้หากคุณมีหรือตั้งค่าคำสั่งเปลี่ยนชื่อ (เช่นผ่านทางการติดตั้งชงใน Mac):

rename --lower-case --force somedir/*

9
... หากคุณตั้งค่าการเปลี่ยนชื่อเป็นครั้งแรกเช่นผ่านbrew install rename
pduersteler

3
เปลี่ยนชื่อ 'y / AZ / az /' *
Stephen

4
--lower-case? ไม่อย่างนั้นใน Arch Linux อย่างน้อยก็น่าเศร้า

3
renameไม่ใช่ทุบตีในตัว มันเป็นยูทิลิตี้ภายนอกและไวยากรณ์จะแตกต่างกันไปขึ้นอยู่กับรุ่นที่คุณติดตั้ง คำตอบนี้ไม่เพียงพอสำหรับโซลูชันแบบพกพา "สำหรับระบบปฏิบัติการยูนิกซ์" ตามที่อ้างสิทธิ์
Corey Goldberg

2
เพิ่งตรวจสอบrenameคำสั่งที่รวมอยู่ใน Fedora ล่าสุด (28) ผ่านutil-linux-2.31แพคเกจไม่มี--lower-caseตัวเลือก
niXar

11

สิ่งนี้ใช้ได้กับCentOS / Red Hat Linuxหรือการกระจายอื่น ๆ ที่ไม่มีrenameสคริปต์ Perl:

for i in $( ls | grep [A-Z] ); do mv -i "$i" "`echo $i | tr 'A-Z' 'a-z'`"; done

แหล่งที่มา: เปลี่ยนชื่อไฟล์ทั้งหมดจากตัวพิมพ์ใหญ่เป็นตัวพิมพ์เล็ก

(ในการแจกแจงบางrenameคำสั่งเริ่มต้นมาจาก util-linux และเป็นเครื่องมือที่แตกต่างกันและเข้ากันไม่ได้)


ใช้งานได้ในไดเรกทอรีเดียวเท่านั้นไม่ใช่แบบเรียกซ้ำ
Bram

คูล .. ทำงานได้ดี
ราม

6

วิธีที่ง่ายที่สุดที่ฉันพบใน Mac OS X คือใช้แพ็คเกจเปลี่ยนชื่อจากhttp://plasmasturm.org/code/rename/ :

brew install rename
rename --force --lower-case --nows *

- บังคับใช้การเปลี่ยนชื่อแม้ว่าไฟล์ที่มีชื่อปลายทางมีอยู่แล้ว

- ตัวพิมพ์เล็กแปลงชื่อไฟล์เป็นตัวพิมพ์เล็กทั้งหมด

--nows แทนที่ลำดับทั้งหมดของช่องว่างในชื่อไฟล์ด้วยอักขระขีดล่างเดียว


5

นี่คือวิธีแก้ปัญหาย่อยของฉันโดยใช้สคริปต์เปลือก Bash:

#!/bin/bash
# First, rename all folders
for f in `find . -depth ! -name CVS -type d`; do
   g=`dirname "$f"`/`basename "$f" | tr '[A-Z]' '[a-z]'`
   if [ "xxx$f" != "xxx$g" ]; then
      echo "Renaming folder $f"
      mv -f "$f" "$g"
   fi
done

# Now, rename all files
for f in `find . ! -type d`; do
   g=`dirname "$f"`/`basename "$f" | tr '[A-Z]' '[a-z]'`
   if [ "xxx$f" != "xxx$g" ]; then
      echo "Renaming file $f"
      mv -f "$f" "$g"
   fi
done

โฟลเดอร์ถูกเปลี่ยนชื่ออย่างถูกต้องและmvไม่ถามคำถามเมื่อสิทธิ์ไม่ตรงกันและโฟลเดอร์ CVS จะไม่ถูกเปลี่ยนชื่อ (ไฟล์ควบคุม CVS ภายในโฟลเดอร์นั้นยังคงถูกเปลี่ยนชื่อ แต่น่าเสียดายที่)

เนื่องจาก "find -depth" และ "find | sort -r" ทั้งคู่ส่งคืนรายการโฟลเดอร์ตามลำดับที่ใช้งานได้สำหรับการเปลี่ยนชื่อฉันจึงต้องการใช้ "-depth" เพื่อค้นหาโฟลเดอร์


การค้นหาครั้งแรกของคุณไม่ทำงาน ลอง "mkdir -p A / B / C" แล้วเรียกใช้สคริปต์ของคุณ
tzot

4

คำถามเดิมขอให้ละเว้นไดเรกทอรี SVN และ CVS ซึ่งสามารถทำได้โดยการเพิ่ม -prune ไปยังคำสั่ง find เช่นไม่สนใจ CVS:

find . -name CVS -prune -o -exec mv '{}' `echo {} | tr '[A-Z]' '[a-z]'` \; -print

[แก้ไข] ฉันลองใช้แล้วและการฝังตัวพิมพ์เล็กในการค้นหานั้นใช้ไม่ได้ด้วยเหตุผลที่ฉันไม่เข้าใจ ดังนั้นแก้ไขสิ่งนี้เป็น:

$> cat > tolower
#!/bin/bash
mv $1 `echo $1 | tr '[:upper:]' '[:lower:]'`
^D
$> chmod u+x tolower 
$> find . -name CVS -prune -o -exec tolower '{}'  \;

เอียน


4

การใช้เครื่องมือแก้ไขชื่อไฟล์ของ Larry Wall:

$op = shift or die $help;
chomp(@ARGV = <STDIN>) unless @ARGV;
for (@ARGV) {
    $was = $_;
    eval $op;
    die $@ if $@;
    rename($was,$_) unless $was eq $_;
}

มันง่ายเหมือน

find | fix 'tr/A-Z/a-z/'

( fixแน่นอนว่าสคริปต์อยู่ด้านบน)


3

นี่คือเชลล์สคริปต์ขนาดเล็กที่ทำสิ่งที่คุณร้องขอ:

root_directory="${1?-please specify parent directory}"
do_it () {
    awk '{ lc= tolower($0); if (lc != $0) print "mv \""  $0 "\" \"" lc "\"" }' | sh
}
# first the folders
find "$root_directory" -depth -type d | do_it
find "$root_directory" ! -type d | do_it

หมายเหตุการกระทำที่ลึกลงไปในการค้นหาครั้งแรก


1
สิ่งเดียวที่ทำงานบน Mac ได้จากทั้งเธรด ขอบคุณมาก!
YemSalat

2

ไม่ใช่แบบพกพา Zsh เท่านั้น แต่ค่อนข้างกระชับ

ขั้นแรกตรวจสอบให้แน่ใจว่าzmvโหลดแล้ว

autoload -U zmv

นอกจากนี้ตรวจสอบให้แน่ใจว่าextendedglobเปิดอยู่:

setopt extendedglob

จากนั้นใช้:

zmv '(**/)(*)~CVS~**/CVS' '${1}${(L)2}'

ไปยังไฟล์ตัวพิมพ์เล็กซ้ำและไดเรกทอรีที่ชื่อไม่ได้เป็นCVS


2
for f in `find -depth`; do mv ${f} ${f,,} ; done

find -depthพิมพ์แต่ละไฟล์และไดเรกทอรีด้วยเนื้อหาของไดเรกทอรีที่พิมพ์ก่อนไดเรกทอรีเอง ${f,,}ลดขนาดชื่อไฟล์


สิ่งนี้ใช้ไม่ได้: มันเปลี่ยนชื่อไดเรกทอรีก่อนที่จะทำงานกับเนื้อหาเช่นความพยายามในภายหลังในเนื้อหาล้มเหลว
พรุน

การเพิ่มการ-depthแก้ไขที่! นี่เป็นวิธีแก้ปัญหาที่รวดเร็วจริงๆ แต่แน่นอนโดยไม่ต้องใช้-print0ตัวเลือกในการค้นหามันไม่น่าเชื่อถือที่สุด
jpaugh

@jpaugh ไม่มันไม่ได้ มันจะพยายามเปลี่ยนชื่อ. /FOO/BAR เป็น ./foo/bar แต่. / foo ยังไม่มีอยู่ในขณะนั้น
oisyn

2

ด้วย MacOS

ติดตั้งrenameแพ็คเกจ

brew install rename

ใช้,

find . -iname "*.py" -type f | xargs -I% rename -c -f  "%"                       

คำสั่งนี้ค้นหาไฟล์ทั้งหมดที่มี*.pyนามสกุลและแปลงชื่อไฟล์เป็นตัวพิมพ์เล็ก

`f` - forces a rename

ตัวอย่างเช่น,

$ find . -iname "*.py" -type f
./sample/Sample_File.py
./sample_file.py
$ find . -iname "*.py" -type f | xargs -I% rename -c -f  "%"
$ find . -iname "*.py" -type f
./sample/sample_file.py
./sample_file.py

ทำไมคุณถึงใช้-Iตัวเลือกสำหรับxargsที่นี่?
Victor Yarema

- Iธงไม่ได้รับคำสั่ง xargsมันถูกใช้เมื่อเรารันคำสั่งหลายกับ นี่คือตัวอย่างของการใช้หลายคำสั่งด้วยxargs cat foo.txt | xargs -I % sh -c 'echo %; mkdir %' คุณสามารถเรียกใช้โดยไม่-Iต้องการfind . -iname "*.py" -type f | xargs -I% rename -c -f "%"
akilesh raj

2

ใช้เรียงพิมพ์ :

typeset -l new        # Always lowercase
find $topPoint |      # Not using xargs to make this more readable
  while read old
  do new="$old"       # $new is a lowercase version of $old
     mv "$old" "$new" # Quotes for those annoying embedded spaces
  done

สำหรับ Windows emulations เช่นGit Bashอาจล้มเหลวเนื่องจาก Windows ไม่คำนึงถึงตัวพิมพ์เล็กและใหญ่ สำหรับผู้ที่เพิ่มขั้นตอนที่mvเป็นไฟล์เป็นชื่ออื่นก่อนเช่น '$ old.tmp' $newและหลังจากนั้นจะ


1

มีความยาว แต่"ใช้งานได้โดยไม่ต้องแปลกใจ & ไม่มีการติดตั้ง"

สคริปต์นี้จัดการชื่อไฟล์ด้วยช่องว่างอัญประกาศอักขระผิดปกติอื่น ๆและ Unicode ทำงานบนระบบไฟล์แบบไม่คำนึงถึงขนาดตัวพิมพ์และสภาพแวดล้อม Unix-y ส่วนใหญ่ที่ติดตั้ง bash และ awk (เกือบทั้งหมด) นอกจากนี้ยังรายงานการชนกันหากมี (ออกจากชื่อไฟล์เป็นตัวพิมพ์ใหญ่) และแน่นอนว่าจะเปลี่ยนชื่อไฟล์และไดเรกทอรีทั้งสองและทำงานซ้ำ ในที่สุดมันก็ปรับได้สูง: คุณสามารถปรับแต่งคำสั่ง find เพื่อกำหนดเป้าหมายไฟล์ / dirs ที่คุณต้องการและคุณสามารถปรับแต่ง awk เพื่อทำการปรับเปลี่ยนชื่ออื่น ๆ โปรดทราบว่าด้วยการ "จัดการ Unicode" ฉันหมายความว่ามันจะแปลงกรณีของพวกเขา (ไม่สนใจพวกเขาเหมือนคำตอบที่ใช้tr)

# adapt the following command _IF_ you want to deal with specific files/dirs
find . -depth -mindepth 1 -exec bash -c '
  for file do
    # adapt the awk command if you wish to rename to something other than lowercase
    newname=$(dirname "$file")/$(basename "$file" | awk "{print tolower(\$0)}")
    if [ "$file" != "$newname" ] ; then
        # the extra step with the temp filename is for case-insensitive filesystems
        if [ ! -e "$newname" ] && [ ! -e "$newname.lcrnm.tmp" ] ; then
           mv -T "$file" "$newname.lcrnm.tmp" && mv -T "$newname.lcrnm.tmp" "$newname" 
        else
           echo "ERROR: Name already exists: $newname"
        fi
    fi    
  done
' sh {} +

อ้างอิง

สคริปต์ของฉันขึ้นอยู่กับคำตอบที่ยอดเยี่ยมเหล่านี้:

/unix/9496/looping-through-files-with-spaces-in-the-names

วิธีการแปลงสตริงเป็นตัวพิมพ์เล็กใน Bash?


1

มันทำงานได้ดีบน macOS ด้วย:

ruby -e "Dir['*'].each { |p| File.rename(p, p.downcase) }"

นี่เป็นสิ่งที่ดีเป็นพิเศษเนื่องจาก Ruby มาพร้อมกับ macOS
jxmorris12

1

ฉันต้องทำสิ่งนี้ในการติดตั้ง Cygwin บน Windows 7 และพบว่าฉันได้รับข้อผิดพลาดทางไวยากรณ์พร้อมคำแนะนำจากด้านบนที่ฉันลอง (แม้ว่าฉันอาจพลาดตัวเลือกที่ใช้งานได้) อย่างไรก็ตามวิธีการแก้ปัญหานี้ตรงจากฟอรั่ม Ubuntu ที่ทำออกมาได้ไม่ดี :-)

ls | while read upName; do loName=`echo "${upName}" | tr '[:upper:]' '[:lower:]'`; mv "$upName" "$loName"; done

(หมายเหตุ: ก่อนหน้านี้ฉันได้เปลี่ยนช่องว่างด้วยเครื่องหมายขีดล่างโดยใช้:

for f in *\ *; do mv "$f" "${f// /_}"; done

)


1

ใน OS X mv -fแสดงข้อผิดพลาด "ไฟล์เดียวกัน" ดังนั้นฉันจึงเปลี่ยนชื่อสองครั้ง:

for i in `find . -name "*" -type f |grep -e "[A-Z]"`; do j=`echo $i | tr '[A-Z]' '[a-z]' | sed s/\-1$//`; mv $i $i-1; mv $i-1 $j; done

1

ฉันจะไปถึง Python ในสถานการณ์นี้เพื่อหลีกเลี่ยงการสมมติเส้นทางโดยไม่มีช่องว่างหรือสแลช ฉันยังพบว่ามีแนวโน้มที่จะได้รับการติดตั้งในสถานที่มากกว่าpython2rename

#!/usr/bin/env python2
import sys, os

def rename_dir(directory):
  print('DEBUG: rename('+directory+')')

  # Rename current directory if needed
  os.rename(directory, directory.lower())
  directory = directory.lower()

  # Rename children
  for fn in os.listdir(directory):
    path = os.path.join(directory, fn)
    os.rename(path, path.lower())
    path = path.lower()

    # Rename children within, if this child is a directory
    if os.path.isdir(path):
        rename_dir(path)

# Run program, using the first argument passed to this Python script as the name of the folder
rename_dir(sys.argv[1])

พูดเกี่ยวกับการทำให้มันซับซ้อน ... แค่ทำ .. เปลี่ยนชื่อ 'y / AZ / az /' *
Stephen

1
@ สตีเฟ่นสมมติว่าคุณมีสิทธิ์การเข้าถึงของผู้ดูแลระบบเพื่อเปลี่ยนชื่อการติดตั้ง ฉันจำเป็นต้องลบข้อมูลบนระบบที่ฉันไม่สามารถติดตั้งซอฟต์แวร์อื่น ๆ ได้บ่อย ใน Ubuntus เมื่อเร็ว ๆ นี้จะติดตั้งเฉพาะเมื่อมี perl
John Foley

1

หากคุณใช้Arch Linuxคุณสามารถติดตั้งrename) แพ็คเกจAURที่ให้renamexmคำสั่งว่า/usr/bin/renamexmสามารถเรียกใช้งานได้และหน้าคู่มือพร้อมกับมัน

มันเป็นเครื่องมือที่ทรงพลังจริงๆในการเปลี่ยนชื่อไฟล์และไดเรกทอรีอย่างรวดเร็ว

แปลงเป็นตัวพิมพ์เล็ก

rename -l Developers.mp3 # or --lowcase

แปลงเป็นตัวพิมพ์ใหญ่

rename -u developers.mp3 # or --upcase, long option

ตัวเลือกอื่น

-R --recursive # directory and its children

-t --test # Dry run, output but don't rename

-o --owner # Change file owner as well to user specified

-v --verbose # Output what file is renamed and its new name

-s/str/str2 # Substitute string on pattern

--yes # Confirm all actions

คุณสามารถดึงไฟล์Developers.mp3จากที่นี่ถ้าจำเป็น;)


1
เปลี่ยนชื่อจากbrewบน macOS ได้-lผูกไว้กับการสร้าง symlink และ-cการแปลงเป็นตัวพิมพ์เล็กดังนั้นระวัง
rien333

0
( find YOURDIR -type d | sort -r;
  find yourdir -type f ) |
grep -v /CVS | grep -v /SVN |
while read f; do mv -v $f `echo $f | tr '[A-Z]' '[a-z]'`; done

ก่อนอื่นให้เปลี่ยนชื่อไดเรกทอรีด้านล่างขึ้นเรียงลำดับ -r (โดยที่ -depth ไม่พร้อมใช้งาน) จากนั้นไฟล์ จากนั้นgrep -v / CVSแทนที่จะหา ... - พรุนเพราะง่ายกว่า สำหรับไดเรกทอรีขนาดใหญ่สำหรับ f ใน ...สามารถล้นบัฟเฟอร์บางเชลล์ ใช้ค้นหา ... | ในขณะที่อ่านเพื่อหลีกเลี่ยง

และใช่ไฟล์นี้จะปิดบังซึ่งแตกต่างกันเฉพาะในกรณี ...


ครั้งแรก: find YOURDIR -type d | sort -rเป็นปัญหามากเกินไป find YOURDIR -depth -type dคุณต้องการ ประการที่สองfind -type fต้องรันหลังจากเปลี่ยนชื่อไดเรกทอรีแล้ว
tzot

0
find . -depth -name '*[A-Z]*'|sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p'|sh

ฉันไม่ได้ลองสคริปต์ที่ซับซ้อนมากขึ้นที่กล่าวถึงที่นี่ แต่ไม่มี commandline version เดียวที่ทำงานให้ฉันใน Synology NAS ของฉัน renameไม่พร้อมใช้งานและรูปแบบต่างๆของความfindล้มเหลวเนื่องจากดูเหมือนจะติดกับชื่อที่เก่ากว่าของเส้นทางที่ถูกเปลี่ยนชื่อแล้ว (เช่นหาก./FOOตามมาด้วยการ./FOO/BARเปลี่ยนชื่อ./FOOเป็น./fooจะยังคงอยู่ในรายการต่อไป./FOO/BARแม้ว่าเส้นทางนั้นจะไม่ถูกต้องอีกต่อไป) . คำสั่งดังกล่าวทำงานให้ฉันโดยไม่มีปัญหาใด ๆ

สิ่งต่อไปนี้คือคำอธิบายของแต่ละส่วนของคำสั่ง:


find . -depth -name '*[A-Z]*'

นี่จะค้นหาไฟล์ใด ๆ จากไดเรกทอรีปัจจุบัน (เปลี่ยน.เป็นไดเรกทอรีใด ๆ ที่คุณต้องการประมวลผล) โดยใช้การค้นหาความลึกก่อน (เช่นจะแสดงรายการ./foo/barก่อน./foo) แต่เฉพาะไฟล์ที่มีอักขระตัวพิมพ์ใหญ่ -nameกรองเฉพาะกับชื่อไฟล์ฐานที่ไม่เส้นทางแบบเต็ม ดังนั้นนี้จะแสดงรายการแต่ไม่./FOO/BAR นี้ก็โอเคที่เราไม่ต้องการที่จะเปลี่ยนชื่อ./FOO/bar ./FOO/barเราต้องการเปลี่ยนชื่อ./FOOแต่มีการระบุไว้ในภายหลัง (นี่คือเหตุผลที่-depthสำคัญ)

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


sed -n 's/\(.*\/\)\(.*\)/mv -n -v -T \1\2 \1\L\2/p'

ส่วนนี้จะอ่านไฟล์ที่ส่งออกโดยfindและจัดรูปแบบพวกเขาในmvคำสั่งโดยใช้การแสดงออกปกติ -nตัวเลือกหยุดsedจากการพิมพ์การป้อนข้อมูลและpคำสั่งในการค้นหาและแทนที่ผล regex ข้อความที่แทนที่

Regex นั้นประกอบด้วยการจับสองครั้ง: ส่วนจนถึงสุดท้าย / (ซึ่งเป็นไดเรกทอรีของไฟล์) และชื่อไฟล์เอง ไดเรกทอรีนั้นยังคงสภาพเหมือนเดิม แต่ชื่อไฟล์จะถูกเปลี่ยนเป็นตัวพิมพ์เล็ก ดังนั้นถ้าfindเอาท์พุทก็จะกลายเป็น./FOO/BAR ตัวเลือกในการทำให้แน่ใจว่าแฟ้มที่มีอยู่พิมพ์เล็กไม่ได้ถูกเขียนทับ ตัวเลือกที่จะทำให้การส่งออกการเปลี่ยนแปลงทุกครั้งที่มันทำให้ (หรือไม่ได้ทำให้ - ถ้ามีอยู่แล้วมันจะออกผลลัพธ์บางอย่างเช่นสังเกตว่าไม่มีการเปลี่ยนแปลงที่ได้รับการทำ) เป็นสิ่งสำคัญมากที่นี่ - มันถือว่าแฟ้มเป้าหมายเป็นไดเรกทอรี สิ่งนี้จะทำให้แน่ใจได้ว่าไม่ได้ย้ายเข้าไปในไดเรกทอรีนั้นหากมีอยู่mv -n -v -T ./FOO/BAR ./FOO/bar-nmv-vmv./FOO/bar./FOO/BAR -> ./FOO/BAR-T./FOO/BAR./FOO/bar

ใช้สิ่งนี้ร่วมกับfindเพื่อสร้างรายการคำสั่งที่จะถูกดำเนินการ (สะดวกในการตรวจสอบสิ่งที่จะทำโดยไม่ต้องทำจริง ๆ )


sh

คำอธิบายนี้ค่อนข้างสวย มันกำหนดเส้นทางmvคำสั่งที่สร้างขึ้นทั้งหมดไปยังล่ามเปลือก คุณสามารถแทนที่ด้วยbashหรือเปลือกที่คุณชื่นชอบ


0

Slugify Rename (regex)

มันไม่ใช่สิ่งที่ OP ต้องการ แต่สิ่งที่ฉันหวังว่าจะพบในหน้านี้:

เวอร์ชัน "slugify" สำหรับการเปลี่ยนชื่อไฟล์เพื่อให้คล้ายกับ URL (เช่นมีเพียงตัวอักษรและตัวเลขจุดและขีดกลาง):

rename "s/[^a-zA-Z0-9\.]+/-/g" filename

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