ไฟล์ Linux mv ที่มีชื่อยาว


19

ใน Linux บางครั้งฉันเปลี่ยนชื่อไฟล์เช่นนี้:

mv dir1/dir2/dir3/file.txt  dir1/dir2/dir3/file.txt.old

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

มีคำสั่งที่อนุญาตให้ฉันทำเวอร์ชันย่อของคำสั่งนั้นหรือไม่? ฉันกำลังคิดอะไรบางอย่างเช่น:

mv dir1/dir2/dir3/file.txt  file.txt.old

หรืออาจเป็นสิ่งที่ชอบ (เพื่อต่อท้ายชื่อ):

mv dir1/dir2/dir3/file.txt  {}.old

เป้าหมายของฉันคือไม่ต้องระบุเส้นทางที่สมบูรณ์อีกครั้ง

ฉันรู้ว่า "ตัวอย่าง" ที่ฉันเขียนไม่ได้ผล แต่เป็นเพียงความคิดว่าฉันต้องการทำอะไร

ฉันไม่ต้องการที่จะ cd ในไดเรกทอรี


8
ทำไมคุณไม่เปลี่ยนเป็นไดเรกทอรี? มันรวดเร็วและแก้ปัญหาของคุณ
Michael Hampton

ฉันกำลังจัดการกับไดเรกทอรีย่อยจำนวนมากจากที่ตั้งเดียวกันนี้มันช้าลงถ้าฉันต้องกลับมาที่พ่อแม่ผู้ปกครองนี้ทุกครั้ง
santiago arizti

3
ไม่มีใครพูดว่าคุณต้องเปลี่ยนไปที่สารบบอื่นเพียงแค่สิ่งที่คุณต้องการ
Michael Hampton

โปรดทราบว่า(cd dir1/dir2/dir3 && exec mv file.txt{,.old})มีประสิทธิภาพเช่นเดียวกับรหัสที่ไม่มีกระบวนการย่อยอย่างมีประสิทธิภาพเนื่องจากexecจะหลีกเลี่ยงการทำงานfork()ระหว่างการเรียกใช้คำสั่งภายนอกดังนั้นคุณจึงมีทางแยกเพียงทางเดียว
ชาร์ลส์ดัฟฟี่

คำตอบ:


45

สำหรับไฟล์เดียวลอง

mv dir1/dir2/dir3/file.{txt,txt.old}

เมื่อX{a,b}โครงสร้างขยายไปถึงXa Xbคุณสามารถดูตัวอย่างได้โดยใช้

echo dir1/dir2/dir3/file.{txt,txt.old}

เพื่อดูว่าเหมาะสมกับความต้องการของคุณหรือไม่

บันทึก:

  1. สำหรับหลายไฟล์

    mv dir1/dir2/dir3/file{1,2,3}.{txt,txt.old}
    

ไม่น่าจะขยายไปยังสิ่งที่คุณต้องการ (สิ่งนี้จะขยายเป็นแบบรวมกันของ file.txt file1.txt.old file2.txt ... )

  1. {txt,txt.old}สามารถ shorterned ไป{,.old}ตามความคิดเห็น

  2. หากชื่อไดเรกทอรีไม่น่าเชื่อถือคุณสามารถใช้อักขระตัวแทนได้

    mv *1/*2/d*/*.{,old}
    

สำหรับการใช้งานหลายไฟล์ rename

rename -n s/txt/old.txt/ dir1/dir2/dir3/file*.txt 

วาง-nเพื่อให้มีการเปลี่ยนชื่อที่มีประสิทธิภาพ


1
ดีฉันไม่รู้จักวิธีนี้ในการขยาย! ขอบคุณ
santiago arizti

14
จะmv dir1/dir2/dir3/file.txt{,.old}ไม่ทำงานด้วยและจะสั้นกว่าด้วยใช่ไหม
Josh

3
@ Josh ใช่มันทำงานได้อย่างสมบูรณ์และต้องการการกดแป้นน้อย ฉันใช้สิ่งก่อสร้างนี้เป็นประจำ
rlf

2
เป็นเรื่องตลกที่คุณจะสามารถใช้เปลือก Linux ได้นานหลายปีและยังคงพบกับเทคนิคใหม่ตลอดเวลา
santiago arizti

ฉันเดาว่า "กลเม็ด" ทั้งหมดนั้นจะชัดเจนกว่านี้ถ้าฉันมีการฝึกอบรมอย่างเป็นทางการในภาษาทุบตี แต่ฉันเพิ่งเรียนรู้มากพอที่จะเข้ากันได้
santiago arizti

6

คำสั่งrenameเปลี่ยนชื่อไฟล์ที่ตรงกันทั้งหมด วัตถุประสงค์หลักคือการเปลี่ยนชื่อไฟล์หลายไฟล์ แต่ถ้านิพจน์ Perl ตรงกับไฟล์เดียวก็จะเปลี่ยนชื่อไฟล์เดียวเท่านั้น สำหรับรายละเอียดและไวยากรณ์ที่เฉพาะเจาะจง distro โปรดอ่าน manpage man renameนี้:

ตัวอย่างการใช้งาน: เปลี่ยนชื่อ "/path/file.txt" เป็น "/path/file.txt.old":

rename 's/file.txt/file.txt.old/g' /path/file.txt

สัญกรณ์สั้น (ขอบคุณ shalomb):

rename 's/$/.old/' /path/file.txt
rename '$_.=".old"' /path/file.txt

rename -nสำหรับการใช้งานแห้ง

ตัวอย่างและรายละเอียดเพิ่มเติมสามารถดูได้ที่https://thepcspy.com/read/bulk-rename-files-in-ubuntu/


เจ๋งฉันรู้เกี่ยวกับคำสั่งเปลี่ยนชื่อแค่ไม่เคยรู้เลยว่ามันจะทำอย่างไรขอบคุณ!
santiago arizti

6
น่าเสียดายที่ลีนุกซ์รุ่นต่าง ๆ มีrenameคำสั่งต่างกันซึ่งมีพฤติกรรมที่แตกต่างกันโดยสิ้นเชิง
kasperd

1
สำหรับงานนี้โดยเฉพาะการเปลี่ยนชื่อโดยต่อท้าย.oldชื่อไฟล์อาจจะสะดวกกว่าที่จะทำrename 's/$/.old/' /path/to/file.txtหรือrename '$_.=".old"' /path/to/file.txt
shalomb

@Fabian - ฉันไม่ใช่ nitpicking เพียงแค่เล็งหา "มือที่สั้นที่สุด" สำหรับสิ่งที่ดูเหมือนว่าจะเป็นสำนวนที่ใช้บ่อยที่ OP กำลังมองหา :)
shalomb

4

สำหรับกรณีใช้ครั้งเดียวถ้าฉันไม่ต้องการเปลี่ยนไดเรกทอรีปัจจุบันฉันอาจใช้ sub-shell:

(cd dir1/dir2/dir3/ && mv file.txt file.txt.old)

เนื่องจากคุณcdอยู่ในเชลล์ย่อยคุณไม่ได้เปลี่ยนไดเรกทอรีในเชลล์จริง


4
เร็วขึ้นและปลอดภัยกว่าในการใช้&& exec mv- วิธีนี้คุณจะไม่พยายามเปลี่ยนชื่อหากcdล้มเหลวและexecใช้เชลล์ย่อยดังนั้นจึงหลีกเลี่ยงการปรับโทษ
ชาร์ลส์ดัฟฟี่

เห็นด้วยกับ&& สำหรับกรณีที่ฉันพูดว่าฉันจะไม่กังวลเกี่ยวกับค่าใช้จ่ายของเชลล์ย่อย (ทำให้มันง่าย: ความสามารถในการจำได้ง่ายว่าจะทำอย่างไรจึงเป็น IMO ที่สำคัญกว่า)
อดัม

ฉันเถียงว่าถ้าคุณกำลังจะไปจำได้ว่าทางเดียวเท่านั้นที่จำวิธีที่มีประสิทธิภาพจะช่วยให้แน่ใจว่าคุณไม่ได้ไปเส้นทางที่ไม่มีประสิทธิภาพในกรณีที่มันไม่เป็นเรื่อง
Charles Duffy

4

ฉันชอบวิธีแก้ปัญหาของ @ archemar ในการใช้การขยาย {} เพราะคุณสามารถใช้งานได้เมื่อคุณเริ่มบรรทัดคำสั่งแล้ว นี่คือความเป็นไปได้อื่น ๆ สำหรับความสมบูรณ์:

F="dir1/dir2/dir3/file.txt" ; mv "$F" "$F.old"

(อัญประกาศเป็นสิ่งจำเป็นเฉพาะเมื่อคุณมีช่องว่างหรืออักขระแบ่งคำอื่น ๆ ในชื่อ)

mymv() {
    mv "$1/$2" "$1/$3"
}

mymv dir1/dir2/dir3 file.txt file.txt.old
mymv dir5/dir6/dir7 file.txt file.txt.old

หมายเหตุ:

  • นี่คือไวยากรณ์ของ bash คุณอาจใช้เชลล์อื่น
  • mymv สามารถสตริงใด ๆ ที่เหมาะสมฉันใช้ mymv สำหรับ "ย้ายของฉัน"
  • นิยามฟังก์ชันสามารถใส่ใน. bash_profile ของคุณ

อีกหนึ่ง:

cd dir1/dir2/dir3 ; mv file.txt file.txt.old ; cd -

แต่

(cd dir1/dir2/dir3/ && exec mv file.txt file.txt.old)

(จาก @Adam และ @CharlesDuffy) จะดีกว่าในกรณีที่ซีดีล้มเหลว


1
อย่าใช้mmvมีโปรแกรมชื่อนี้แล้ว
glglgl

1
@glglgl Done :)
Law29

2

หากคุณต้องการป้อนไดเรกทอรีย่อยเพื่อย่อmvคำสั่งให้สั้นลงแต่ต้องการกลับมาที่ไดเรกทอรีปัจจุบันหลังจากนั้นมีสองวิธีในการทำเช่นนั้น หนึ่งคือการใส่cdและmvใน subshell (ตามที่ได้รับการแนะนำแล้ว)

อีกอันคือการใช้pushdและpopdการเปลี่ยนไดเรกทอรี:

pushd dir1/dir2/dir3/; mv file.txt file.txt.old; popd

pushdคำสั่งเป็นเหมือนcdยกเว้นมันเป็นครั้งแรกที่ผลักดันให้ชื่อของไดเรกทอรีปัจจุบันไปยังกอง popdลบชื่อบนออกจากสแต็กและเปลี่ยนเป็นไดเร็กทอรีนั้น


pushdและpopdเป็นส่วนขยายที่มีไว้สำหรับการใช้งานแบบโต้ตอบ - POSIX แสดงรายการเหล่านั้นอย่างชัดเจนว่า "ผลลัพธ์ไม่ได้ระบุ" และเชลล์ที่สร้างขึ้นสำหรับการเรียกใช้สคริปต์ (เช่นในสภาพแวดล้อมแบบฝังตัวที่น้อยที่สุด) ไม่ต้องการการสนับสนุน
Charles Duffy


0

วิธีแก้ปัญหาที่เกี่ยวข้อง: mv something{.txt,.txt.old}กำลังใช้ "bashism" หากคุณต้องการวิธีพกพามากขึ้นโดยใช้การปรับเปลี่ยนตัวแปรทั่วไป:

# rename all files "file*.txt" of directory /dir1/dir2/dir3 into file*.txt.old:
for f in dir1/dir2/dir3/file*.txt ; do
  mv "$f" "${f/.txt/.txt.old}"  # note there are no terminating "/"
done


# "${var/A/B}" is the content of var with the first occurence of "A" replaced by "B"

2
ดูpubs.opengroup.org/onlinepubs/009695399/utilities/ …สำหรับข้อมูลจำเพาะ POSIX ที่เกี่ยวข้อง - ${var/text/replacement}คือการตีตัวเอง
ชาร์ลส์ดัฟฟี่

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