Saya memiliki folder bernama /home/user/temps
yang memiliki 487 folder. Di setiap folder saya memiliki file bernama thumb.png.
Saya ingin menyalin semua file bernama thumb.png ke folder terpisah dan menamainya berdasarkan folder asalnya.
Saya memiliki folder bernama /home/user/temps
yang memiliki 487 folder. Di setiap folder saya memiliki file bernama thumb.png.
Saya ingin menyalin semua file bernama thumb.png ke folder terpisah dan menamainya berdasarkan folder asalnya.
Jawaban:
Ini dia:
for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;
edit:
omong-omong kanonis, omong-omong, adalah bahwa menggunakan find
untuk ini adalah ide yang buruk - hanya menggunakan ekspansi shell jauh lebih dapat diandalkan. Juga, ini mengasumsikan bash
, tapi saya pikir itu asumsi yang aman :)
edit 2:
untuk kejelasan, saya akan memecahnya:
# 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;
detail pada ${var/Pattern/Replacement}
konstruk dapat ditemukan di sini .
tanda kutip di cp
baris penting untuk menangani spasi dan baris baru, dll. dalam nama file.
new_file/\/thumb
?
${VARIABLE/PATTTERN/REPLACEMENT}
menghasilkan nilai VARIABLE
tetapi dengan pola yang diganti oleh teks pengganti. Di sini polanya /thumb
( /
kebutuhan untuk melarikan diri sehingga tidak terlihat ${new_file//PATTERN/REPLACEMENT}
, yang menjadikannya pengganti global alih-alih pengganti yang muncul pertama kali) dan teks pengganti kosong.
/home/user/temps
, yang tidak jelas dari pertanyaan. Jika tidak, Anda perlu mencari atau **
.
Ini berfungsi untuk subdirektori dalam yang sewenang-wenang:
$ 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'
Bagian interessting adalah ekspansi parameter ${NAME//\//_}
. Dibutuhkan konten NAME
, dan menggantikan setiap kejadian /
dengan _
.
Catatan: hasilnya tergantung pada direktori kerja dan parameter path untuk find. Saya menjalankan perintah dari direktori induk temps. Ganti cp
dengan echo
percobaan.
Kode pembantu pendek:
#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}"
#
mv "$1" ../tmp/"${1//\//_}"
beri nama 'deslash.sh' dan buat itu dapat dieksekusi. Sebut saja dengan:
find -type f -name thumb.png -exec ./deslash.sh {} ";"
Ini akan gagal, jika ada tabrakan
a/b/thumb.png # and
a_b/thumb.png
tapi itu tidak bisa dihindari.
Coba ini
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
Edit
Saya telah menambahkan penawaran jika ada nama dir Anda yang memiliki karakter white-space yang tertanam di dalamnya.
Saya juga telah mengubah ini jadi itu hanya akan mencetak perintah yang akan dieksekusi. Periksa output skrip untuk memastikan semua file / nama path terlihat benar. Saat Anda yakin tidak ada masalah dengan perintah yang akan dieksekusi, hapus echo
.
mv -i ./A A/thumb.png ../tmp/.png
folder "A A" saya, ia menghasilkan: - semua file diakhiri dengan ../tmp/.png (../tmp adalah dir target saya).
find -type d
dan melihat hasilnya. Apakah itu mendapatkan semua direktori yang Anda harapkan? Seharusnya, jika tidak, tambahkan beberapa output untuk menunjukkan masalah. Semoga berhasil.
read dir
melakukan pemisahan kata, dan mengambil, dari direktori a\nb
a dan b sebagai dua contoh, yang tidak bisa diselesaikan oleh masking.
Untuk menyalin Anda memerlukan perintah cp , dan untuk mengganti nama untuk linux sama dengan memindahkan file, jadi Anda harus melakukannya dengan perintah mv . Di Linux Anda selalu harus menentukan keseluruhan path, dari sumbernya, jika Anda berada di folder lain, dan ke folder tujuan, tentu saja. Saya akan menjadi seperti ini, untuk salinan:
cp /source_path/file /destination_path/
atau untuk mengganti nama atau pindah
mv /source_path/old_file /destination_path/new_name_file