Cara menyalin setiap file ke-4 dalam folder

15

Saya memiliki banyak file di folder, bernama like 00802_Bla_Aquarium_XXXXX.jpg. Sekarang saya harus menyalin setiap file ke- 4 ke subfolder, dengan mengatakan selected/.

00802_Bla_Aquarium_00020.jpg <= this one
00802_Bla_Aquarium_00021.jpg
00802_Bla_Aquarium_00022.jpg
00802_Bla_Aquarium_00023.jpg
00802_Bla_Aquarium_00024.jpg <= this one
00802_Bla_Aquarium_00025.jpg
00802_Bla_Aquarium_00026.jpg
00802_Bla_Aquarium_00027.jpg
00802_Bla_Aquarium_00028.jpg <= this one
00802_Bla_Aquarium_00029.jpg

Bagaimana saya melakukan ini?

aebersold
sumber
Anda mungkin dapat melakukan seperti solusi untuk superuser.com/q/396536/87552 pada beberapa output ls. Lihat juga stackoverflow.com/q/4553751/789593 yang menanyakan setiap baris kedua.
NN
Jika diberi nomor dan Anda tahu nomor terakhir, Anda dapat mempertimbangkan variasifor n in $(seq -w 20 4 200); do cp "00802_..._00${n}" ...; done
Ulrich Schwarz

Jawaban:

12

Dengan zsh, Anda dapat melakukan:

n=0; cp 00802_Bla_Aquarium_?????.jpg(^e:'((n++%4))':) /some/place

MUNGKIN, ide yang sama, hanya sedikit lebih verbose:

# put the file list in the positional parameters ($1, $2...).
# the files are sorted in alphanumeric order by the shell globbing
set -- 00802_Bla_Aquarium_?????.jpg

n=0
# loop through the files, increasing a counter at each iteration.
for i do
  # every 4th iteration, append the current file to the end of the list
  [ "$(($n % 4))" -eq 0 ] && set -- "$@" "$i"

  # and pop the current file from the head of the list
  shift
  n=$(($n + 1))
done

# now "$@" contains the files that have been appended.
cp -- "$@" /some/place

Karena nama file tersebut tidak mengandung karakter kosong atau karakter pengganti, Anda juga dapat melakukan:

cp $(printf '%s\n' 00802_Bla_Aquarium_?????.jpg | awk 'NR%4 == 1') /some/place
Stéphane Chazelas
sumber
Bisakah Anda memberikan komentar juga dalam kode posix
Rahul Patil
@ ChrisDown, for i doadalah standar dan sebenarnya lebih portabel daripada for i; dodan merupakan cara kanonik untuk mengulang parameter posisi.
Stéphane Chazelas
7

Dalam bash, kemungkinan lucu, itu akan bekerja dengan baik di sini:

cp 00802_Bla_Aquarium_*{00..99..4}.jpg selected

Itu jelas jawaban terpendek dan paling efisien: tidak ada subshell, tidak ada loop, tidak ada pipa, tidak ada awkproses eksternal lingkungan; hanya satu garpu untuk cp(yang tidak dapat Anda hindari pula) dan satu ekspansi bash brace dan glob (yang dapat Anda singkirkan sama sekali karena Anda tahu berapa banyak file yang Anda miliki).

gniourf_gniourf
sumber
4
… Dan 2 asumsi: file diberi nomor secara terus menerus dan yang pertama dapat dibagi dengan 4.
manatwork
@manatwork tidak masalah jika yang pertama tidak dapat dibagi oleh 4: misalnya, cp 00802_Bla_Aquarium_*{03..99..4}.jpg selectedjika Anda mau 3 mod 4. (Saya menggunakan fakta indah bahwa 100 dapat dibagi 4). Sekarang, tentang file-file yang diberi nomor terus-menerus, semua jawaban lain menganggapnya sama.
gniourf_gniourf
Jawaban mana yang mengasumsikan penomoran kontinu? Saya hanya menemukan komentar Ulrich Schwarz dan tidak ada jawaban seperti itu.
manatwork
5

Cukup dengan bash, Anda dapat melakukan:

n=0
for file in ./*.jpg; do
   test $n -eq 0 && cp "$file" selected/
   n=$((n+1))
   n=$((n%4))
done

Pola ./*.jpgtersebut akan diganti oleh daftar nama file yang diurutkan berdasarkan abjad seperti yang dinyatakan oleh bash man, jadi itu harus sesuai dengan tujuan Anda.

jfg956
sumber
Di bash, tiga baris Anda dalam forlingkaran bisa diganti dengan hanya baris ini: (((++n)%4)) || cp "$file" selected/. ;-). Masalahnya adalah bahwa Anda forking pada cpuntuk setiap file yang tidak benar-benar efisien.
gniourf_gniourf
1

Jika Anda telah rubymenginstal, Anda dapat menggunakan one-liner berikut. Perhatikan bahwa ini mengasumsikan bahwa direktori yang dipilih ada.

ruby -rfileutils -e 'files = Dir.glob("*.jpg").each_slice(4) { |file| FileUtils.cp(file.first, "selected/" + file.first) }'

Dibutuhkan daftar semua file dengan ekstensi .jpg di direktori saat ini dan mengirisnya menjadi daftar empat elemen dan menyalin elemen pertama dari setiap daftar tersebut ke direktori yang dipilih di direktori saat ini.

NN
sumber
1

Jika Anda tahu Anda tidak akan memiliki baris baru dalam nama file Anda, Anda dapat menggunakan:

find . -maxdepth 1 -name "*.jpg" | sort | while IFS= read -r file; do
  cp "$file" selected/
  IFS= read -r; IFS= read -r; IFS= read -r
done
jfg956
sumber
@Gilles: terima kasih untuk hasil editnya. Saya menghapus variabel file dalam 3 read, karena saya ingin menunjukkan bahwa mereka tidak diperlukan.
jfg956
1

Anda dapat menggunakan manajer file GUI dan mengubah ukuran perbatasan jendela hingga setiap 5 file menempati satu baris, dan kemudian menggunakan mouse untuk memilih kolom pertama ...

John Chain
sumber
-1

Melihat stackoverflow.com/q/4553751/789593 yang menawarkan solusi untuk menyalin setiap detik seperti yang disebutkan @NN, solusi yang sangat sederhana adalah:

  • Hapus file pertama dari folder awal
  • Salin setiap detik dari folder mulai ke folder perantara
  • Salin setiap detik dari folder perantara ke folder terakhir
  • Tambahkan file pertama secara manual

Ini mungkin tidak sangat efisien karena memerlukan sedikit langkah copy tambahan itu harus sangat mudah dilakukan.

Dennis Jaheruddin
sumber