คัดลอกและเปลี่ยนชื่อไฟล์ที่พบในฟังก์ชั่น "ค้นหา" Linux อย่างไร


17

ฉันมีชื่อโฟลเดอร์/home/user/tempsซึ่งมี 487 โฟลเดอร์ ในแต่ละโฟลเดอร์ฉันมีไฟล์ชื่อ thumb.png

ฉันต้องการคัดลอกไฟล์ทั้งหมดที่ชื่อว่า thumb.png ไปยังโฟลเดอร์แยกต่างหากและเปลี่ยนชื่อไฟล์ตามโฟลเดอร์ที่มาจาก


เปลี่ยนชื่อพวกเขาอย่างไร หากคุณแทนที่ตัวคั่นไดเรกทอรีด้วยบางอย่าง - สมมติว่าขีดเส้นใต้ (_) คุณอาจได้รับการชนกับไฟล์ซึ่งมีขีดเส้นใต้อยู่แล้ว นั่นเป็นความจริงสำหรับตัวละครที่ถูกต้องทุกคนและข้าง / และ \ 0 ซึ่งถูกห้ามในชื่อไฟล์ไม่มีที่พักที่ปลอดภัย - ตัวละครใด ๆ อาจสร้างความขัดแย้งได้
ผู้ใช้ที่ไม่รู้จัก

โฟลเดอร์มีโฟลเดอร์ย่อยหรือเพียงแค่โครงสร้างโฟลเดอร์แบบกว้างและกว้างหรือไม่?
ผู้ใช้ที่ไม่รู้จัก

คำตอบ:


8

ไปเลย:

for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;

แก้ไข:

ภูมิปัญญาที่ยอมรับโดยวิธีการคือการใช้ findสำหรับนี้เป็นความคิดที่ไม่ดี - เพียงแค่การใช้การขยายตัวของเปลือกมีความน่าเชื่อถือมากขึ้น นอกจากนี้สมมติว่าbashแต่ฉันคิดว่ามันเป็นสมมติฐานที่ปลอดภัย :)

แก้ไข 2:

เพื่อความชัดเจนฉันจะทำลายมันลง:

# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do

    # replace 'temps' with 'new_folder' in the path
    # '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
    new_file=${file/temps/new_folder};

    # drop '/thumb' from the path
    # '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
    cp "$file" "${new_file/\/thumb/}";
done;

รายละเอียดเกี่ยวกับ${var/Pattern/Replacement}การสร้างที่สามารถพบได้ที่นี่

คำพูดในcpบรรทัดมีความสำคัญในการจัดการช่องว่างและการขึ้นบรรทัดใหม่ ฯลฯ ในชื่อไฟล์


new_file = new_folder? แบ็กสแลชที่มีวัตถุประสงค์ของการทับหน้าnew_file/\/thumbคืออะไร?
ผู้ใช้ที่ไม่รู้จัก

1
@user: ${VARIABLE/PATTTERN/REPLACEMENT}สร้างมูลค่าVARIABLEแต่ด้วยรูปแบบแทนที่ด้วยข้อความแทนที่ ที่นี่รูปแบบคือ/thumb( /ความต้องการที่จะหลบหนีเพื่อให้มันดูไม่เหมือน${new_file//PATTERN/REPLACEMENT}ซึ่งทำให้เป็นการแทนที่ทั่วโลกแทนที่จะเป็นการแทนที่ครั้งแรกที่เกิดขึ้น) และข้อความการแทนที่นั้นว่างเปล่า
Gilles 'หยุดชั่วร้าย'

แน่นอนตอนนี้ฉันเห็นแล้ว :)
ผู้ใช้ที่ไม่รู้จัก

1
คุณกำลังสมมติว่าไดเรกทอรี 487 อยู่ภายใต้โดยตรง/home/user/tempsซึ่งไม่ชัดเจนจากคำถาม หากพวกเขาไม่ได้คุณจะต้องพบ**หรือ
Gilles 'หยุดความชั่วร้าย'

@Gilles - ฉันจริง ๆ แล้วนั่นคือวิธีที่ฉันอ่านคำถาม ขอขอบคุณที่จุดแม้ว่า :)
simon

5

สิ่งนี้ใช้ได้กับไดเรกทอรีย่อยที่มีความลึกตามอำเภอใจ:

$ find temps/ -name "thumb.png" | while IFS= read -r NAME; do cp -v "$NAME" "separate/${NAME//\//_}"; done
`temps/thumb.png' -> `separate/temps_thumb.png'
`temps/dir3/thumb.png' -> `separate/temps_dir3_thumb.png'
`temps/dir3/dir31/thumb.png' -> `separate/temps_dir3_dir31_thumb.png'
`temps/dir3/dir32/thumb.png' -> `separate/temps_dir3_dir32_thumb.png'
`temps/dir1/thumb.png' -> `separate/temps_dir1_thumb.png'
`temps/dir2/thumb.png' -> `separate/temps_dir2_thumb.png'
`temps/dir2/dir21/thumb.png' -> `separate/temps_dir2_dir21_thumb.png'

ส่วน interessting คือการขยายตัวพารามิเตอร์ ${NAME//\//_}มันต้องใช้เนื้อหาของNAMEและแทนที่ทุกการเกิดขึ้นของด้วย/_

หมายเหตุ: ผลลัพธ์ขึ้นอยู่กับไดเร็กทอรีการทำงานและพารามิเตอร์ path สำหรับ find ฉันเรียกใช้งานคำสั่งจากไดเรกทอรีแม่ของ temps แทนที่cpด้วยechoเป็นการทดสอบ


ล้มเหลวในไฟล์ที่มีบรรทัดใหม่ในชื่อของพวกเขา
ผู้ใช้ที่ไม่รู้จัก

ดีที่ทำงานได้ดีมาก สิ่งหนึ่งที่เพิ่มเติมฉันมีไฟล์ zip น้อยในบางไดเรกทอรีย่อยเช่นกัน เป็นไปได้ไหมที่จะดึง imgae จากตรงนั้นเช่นกัน จำ 'zip not tar'
Mirage

1

รหัสผู้ช่วยสั้น:

#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}" 
#
mv "$1" ../tmp/"${1//\//_}"

ลองตั้งชื่อมันว่า 'deslash.sh' และทำให้มันใช้งานได้ โทรไปที่:

find -type f -name thumb.png -exec ./deslash.sh {} ";"    

มันจะล้มเหลวหากมีการชนกัน

a/b/thumb.png # and 
a_b/thumb.png 

แต่นั่นก็หลีกเลี่ยงไม่ได้


0

ลองสิ่งนี้

mkdir /home/user/thumbs
targDir=/home/user/thumbs

cd /home/user/temps

find . -type d | 
 while IFS="" read -r dir ; do
   if [[ -f "${dir}"/thumb.png ]] ; then
     echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
   fi
done

แก้ไข

ฉันได้เพิ่มข้อความในกรณีที่ชื่อ dir ของคุณมีตัวอักษรสีขาวฝังอยู่ในนั้น

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


ฉันมีไฟล์ png บางไฟล์ในโฟลเดอร์ย่อยอื่น ๆ มันจะใช้ได้ไหม
Mirage

สำหรับ "A" "โฟลเดอร์ของฉันมันสร้าง: mv -i ./A A/thumb.png ../tmp/.png- ไฟล์ทั้งหมดสิ้นสุดใน ../tmp/.png (../tmp เป็นเป้าหมายของฉัน dir)
ผู้ใช้ที่ไม่รู้จัก

เพิ่มเครื่องหมายคำพูดและเครื่องหมายปีกกาหยิกรอบ ๆ ตัวแปรทั้งหมดในโค้ดด้านบนเช่น "$ {dir}"
shellter

@ Mirror51 wrote: "ไฟล์ในโฟลเดอร์ย่อยอื่น ๆ จะได้ผล" ใช่มันควรจะเป็น คุณรู้หรือไม่ว่าคุณสามารถรันแต่ละขั้นตอนของสคริปต์นี้แยกจากกัน (หรือเมื่อรวมกันแล้วแต่ละชุดของไพพ์) คุณสามารถดำเนินการเพียงfind -type dและดูผลลัพธ์ ไม่ได้รับไดเรกทอรีทั้งหมดที่คุณคาดหวังหรือไม่ หากเป็นเช่นนั้นโปรดเพิ่มเอาต์พุตบางส่วนเพื่อแสดงปัญหา โชคดี.
shellter

จะไม่ทำงาน read dirดำเนินการแยกคำและรับจากไดเรกทอรีa\nba และ b เป็นสองอินสแตนซ์ซึ่งไม่สามารถปิดบังได้
ผู้ใช้ที่ไม่รู้จัก

-1

ในการคัดลอกคุณต้องการคำสั่งcpและการเปลี่ยนชื่อสำหรับ linux นั้นเหมือนกับการย้ายไฟล์ดังนั้นคุณต้องทำด้วยคำสั่งmv ใน Linux คุณจะต้องระบุเส้นทางทั้งหมดจากแหล่งหากคุณอยู่ในโฟลเดอร์อื่นและไปยังโฟลเดอร์ปลายทางแน่นอน ฉันจะเป็นอย่างนี้เพื่อคัดลอก:

cp /source_path/file /destination_path/

หรือเพื่อเปลี่ยนชื่อหรือย้าย

mv /source_path/old_file /destination_path/new_name_file

นี่เป็นเพียงส่วนย่อยของคำถามของผู้โพสต์ ตอนนี้อธิบายวิธีวนซ้ำไดเรกทอรีและคัดลอกภาพขนาดย่อ :-)

OP ต้องการใช้find

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