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


10

ฉันมีไฟล์นับล้านไฟล์ที่มีระบบเรียกชื่อต่อไปนี้บนเครื่อง Linux:

1559704165_a1ac6f55fef555ee.jpg

ตัวเลข 10 ตัวแรกคือการประทับเวลาและคนที่ตามด้วย a _เป็นรหัสเฉพาะ ฉันต้องการย้ายไฟล์ทั้งหมดที่ตรงกับรหัสไฟล์เฉพาะไปยังโฟลเดอร์อื่น

ฉันพยายามทำสิ่งนี้ในไดเรกทอรีพร้อมไฟล์

find . -maxdepth 1 -type f | ??????????_a1ac*.jpg |xargs mv -t "/home/ubuntu/ntest"

อย่างไรก็ตามฉันได้รับข้อผิดพลาดระบุ:

bash 1559704165_a1ac6f55fef555ee.jpg: command not found

เมื่อฉันลองmv ??????????_a1ac*.jpg ฉันได้รับรายการข้อผิดพลาดนานเกินไป ฉันมีรูปแบบชื่อไฟล์อย่างน้อย 15 รูปแบบ ฉันจะย้ายพวกเขาอย่างไร


1
ทุบตีกล่าวมันทั้งหมด: ก็พยายามที่จะดำเนินการชื่อไฟล์ว่ามันเป็นครั้งแรกในบรรทัดในขั้นตอนที่ 2 ของท่อ (ท่อเวทีของคุณที่ 2: | ??????????_a1ac*.jpg: ทุบตีขยายไปยังหลายชื่อไฟล์ตัวแรก1559704165_a1ac6f55fef555ee.jpgศรีคุณจะจบลง ในขั้นตอนที่สองนั้นพยายามที่จะดำเนินการ: 1559704165_a1ac6f55fef555ee.jpg next_matching_filename 3rd_matching_filename ... nth_matching_filename. ฉันคิดว่าคุณพยายามที่จะกรองไปยังชื่อไฟล์นั้น (ดูคำตอบด้านล่าง)
Olivier Dulac

คำตอบ:


15

คุณควรใช้:

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' \
-exec mv -t destination "{}" +

ดังนั้นmaxdepth 1หมายความว่าคุณต้องการค้นหาในไดเรกทอรีปัจจุบันไม่มีไดเรกทอรีย่อย

type f หมายถึงค้นหาเฉพาะไฟล์

name '??????????_a1ac*.jpg' เป็นรูปแบบที่ตรงกับไฟล์ที่คุณกำลังค้นหา

mv -t destination "{}" +หมายถึงย้ายไฟล์ที่ตรงกันไปยังปลายทาง ที่นี่+เพิ่มไฟล์ที่ตรงกันใหม่ให้กับไฟล์ก่อนหน้าเช่น:

mv -t dest a b c d

abcd นี่คือไฟล์ที่แตกต่างกัน


ขอบคุณสำหรับการตอบคำถามบุคคลนี้ให้รัดกุม แทนที่จะทิ้งวิธีแก้ปัญหาบางทีคุณอาจอธิบายได้ว่าอะไร / ทำไม แทนที่จะเป็นประโยชน์กับคนหนึ่งคนครั้งเดียวมันจะมีประโยชน์กับทุกคนตลอดเวลา มีการถามคำถามเดียวกันและตอบนับครั้งไม่ถ้วนในช่วง 40-50 ปีที่ผ่านมา ปัญหาคือมันไม่เคยอธิบายได้ดี สอนผู้ชายให้ตกปลา .. ในระหว่างนี้: gnu.org/software/findutils/manual/html_node/find_html/ ......และในกรณีนี้บ่อยครั้งที่ Wikipedia มีประโยชน์มากกว่า docs ทางการ: en.wikipedia.org/wiki/Find_ ( Unix)
เสียง

ดูคำตอบที่อัปเดต
Prvt_Yadav

โปรดทราบว่า-tเป็นส่วนขยาย GNU และอาจไม่สามารถใช้กับอนุพันธ์ของ UNIX ประเภทอื่นได้
Kevin

เมื่อคุณพูดว่า"เครื่องหมายอัญประกาศคู่ช่วยป้องกันการแยกคำ" ฉันคิดว่าคุณกำลังอ้างถึง"{}"ในกรณีที่ฉันต้องการชี้ให้เห็น{}ว่าไม่ได้ขยายตัวโดยเปลือกและไม่จำเป็นต้องอ้าง เชลล์ส่งผ่าน{}เพื่อค้นหาและค้นหาเห็น{}และแทนที่ด้วยชื่อพา ธ ค้นหา exec ไม่ได้ใช้ตัวแยกวิเคราะห์เชลล์และไม่ทำการแยกคำของตัวเอง การอ้างว่ามันไม่ได้ทำอันตรายใด ๆ มันเป็นเพียงการให้เหตุผลที่ได้รับไม่ถูกต้องเล็กน้อย
jw013

@ jw013 ขอบคุณ
Prvt_Yadav

11

คำสั่งของคุณ

find . -maxdepth 1 -type f | ??????????_a1ac*.jpg |xargs mv -t "/home/ubuntu/ntest"

ท่อรายการไฟล์ทั้งหมดไปยังไฟล์ทั้งหมด!

find . -maxdepth 1 -type f -name `*_a1ac*.jpg` -print0 |\
xargs  -0 -r mv -t "/home/ubuntu/ntest"

จะทำเคล็ดลับ


1
ขอบคุณมาก ... วิธีการแก้ปัญหาของคุณก็ทำงานเช่นกัน ... ขอบคุณที่ให้ฉันรู้ว่าฉันไปไหนผิด
แอพริค็อต

8

คุณสนิทมาก คุณควรใช้ตัวเลือกในการ-name findและอย่าลืมอ้างรูปแบบ

ดังนั้น

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' |xargs mv -t "/home/ubuntu/ntest"

ขอบคุณมาก ... วิธีการแก้ปัญหาของคุณก็ทำงานเช่นกัน .... ขอบคุณมากที่บอกให้ฉันรู้ว่าฉันใกล้จะแก้ปัญหาแล้ว ... มันเป็นแรงบันดาลใจสำหรับมือใหม่อย่างฉัน
Apricot

1
คุณควรเพิ่ม-print0เป็นอาร์กิวเมนต์สุดท้ายที่จะพบ (แทนค่าเริ่มต้น: -print) และเพิ่ม-0เป็นตัวเลือกแรกที่จะ xargs (เช่น: xargs -0 mv -t "/home/ubuntu/ntest") ด้วยวิธีนี้สามารถจัดการกับชื่อไฟล์แปลก ๆ (มีช่องว่างในนั้นด้วย "newline" ในนั้น ฯลฯ ) สามารถจัดการได้ find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' -print0 |xargs -0 mv -t "/home/ubuntu/ntest" (ใช้ได้กับการค้นหาที่คล้ายกับ GNU เท่านั้น)
Olivier Dulac

2

ไม่ดีเท่าfindโซลูชัน แต่อีกโซลูชันที่ใช้ได้คือการทำให้mvคำสั่งละเอียดยิ่งขึ้น

สิ่งนี้ทำได้ 4096 การเคลื่อนไหวโดยมีจำนวนไฟล์น้อยกว่าที่ย้ายต่อmvการดำเนินการ

FILEPAT=a1ac
for i in $(seq $((0x000)) $((0xfff))); 
do 
   H=$(printf '%x\n' $i)
   mv 1559704165_${FILEPAT}${H}*.jpg /home/ubuntu/ntest
done

นี่เป็นแฮ็คที่ฉลาดสำหรับคนที่ไม่มีfind(ด้วยเหตุผลอะไรก็ตาม)
ป่า

-1

หากคุณต้องการที่จะย้ายไฟล์บนระบบโฮสต์เดียวกันซึ่งผมคิดว่าคุณกำลังทำกับคุณmv, rsyncอาจจะเป็นตัวเลือกที่เร็วขึ้น:

rsync -av --inplace -W /source/??????????_a1ac*.jpg /home/ubuntu/ntest/

--inplaceและ-Wถูกตั้งค่าให้เร่งกระบวนการ

หากสิ่งนี้ทำให้เกิดข้อผิดพลาดอีกครั้งในรายการอาร์กิวเมนต์ที่ยาวเกินไปคุณสามารถฟีดรายการได้rsync

ทำรายการด้วยค้นหาตัวอย่างเช่น

find . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' > /tmp/my_image_list.txt

และมอบให้ rsync

rsync -av --inplace -W --files-from=/tmp/my_image_list.txt /path/to/files /home/ubuntu/ntest/

แหล่งที่มาที่นี่คือ/path/to/filesเพราะrsyncจะจัดการกับรายการที่คุณให้ไว้ว่าสัมพันธ์กับแหล่งที่มาของคุณ


จุดที่เป็นอยู่: rsyncเร็วกว่าmvถ้าไฟล์ที่ไม่ได้อยู่ในระบบแฟ้มเดียวกัน


นี่น่าจะเป็นข้อผิดพลาด "รายการอาร์กิวเมนต์ยาวเกินไป" ที่ OP ได้กล่าวไว้
Grump

@Grump เพื่อหลีกเลี่ยงปัญหานี้ OP สามารถเขียนรายชื่อของไฟล์ที่จะคัดลอกไปยังแฟ้มเช่นนั้นผ่านไปด้วยfind . -maxdepth 1 -type f -name '??????????_a1ac*.jpg' > /tmp/my_image_list.txt rsync --files-from=/tmp/my_image_list.txtจุดอยู่ที่rsyncเร็วขึ้น เว้นแต่ไฟล์จะอยู่ในระบบไฟล์เดียวกันซึ่ง OP ไม่ได้ระบุไว้
Robert Riedl

@RobertRiedl: คุณควรแก้ไขคำตอบและเพิ่มข้อมูลนี้ ความคิดเห็นอาจไม่เที่ยง
NickD

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