Cách sao chép mọi tệp thứ 4 trong một thư mục


15

Tôi có rất nhiều tập tin trong một thư mục, được đặt tên như thế 00802_Bla_Aquarium_XXXXX.jpg. Bây giờ tôi cần sao chép mọi tệp thứ 4 vào thư mục con, nói trong 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

Làm thế nào để tôi làm điều này?


Bạn có thể có thể thực hiện như các giải pháp cho superuser.com/q/396536/87552 trên một số đầu ra của ls. Xem thêm stackoverflow.com/q/4553751/789593 hỏi về mỗi dòng thứ hai.
NN

Nếu chúng được đánh số và bạn biết số cuối cùng, bạn có thể xem xét một biến thể củafor n in $(seq -w 20 4 200); do cp "00802_..._00${n}" ...; done
Ulrich Schwarz

Câu trả lời:


12

Với zsh, bạn có thể làm:

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

POSIXly, cùng một ý tưởng, chỉ dài hơn một chút:

# 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

Vì các tên tệp đó không chứa bất kỳ ký tự trống hoặc ký tự đại diện nào, bạn cũng có thể thực hiện:

cp $(printf '%s\n' 00802_Bla_Aquarium_?????.jpg | awk 'NR%4 == 1') /some/place

Bạn có thể vui lòng đặt bình luận trong mã posix
Rahul Patil

@ChrisDown, for i dolà tiêu chuẩn và thực sự dễ mang theo hơn for i; dovà là cách chính tắc để lặp qua các tham số vị trí.
Stéphane Chazelas

7

Trong bash, một khả năng hài hước, sẽ hoạt động khá tốt ở đây:

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

Đó chắc chắn là câu trả lời ngắn gọn và hiệu quả nhất: không có subshell, không loop, không pipe, không có awkquy trình bên ngoài phường; chỉ cần một ngã ba cp(dù sao bạn cũng không thể tránh được) và một lần mở rộng cú đúp và toàn cầu (rằng bạn có thể thoát khỏi hoàn toàn vì bạn biết bạn có bao nhiêu tệp).


4
Giả định và 2 giả định: các tệp được đánh số liên tục và tệp đầu tiên chia hết cho 4.
manatwork

@manatwork không có vấn đề gì nếu cái đầu tiên không chia hết cho 4: ví dụ: cp 00802_Bla_Aquarium_*{03..99..4}.jpg selectednếu bạn muốn 3 mod 4. (Tôi đang sử dụng một thực tế tuyệt vời là 100 chia hết cho 4). Bây giờ, về các tập tin được đánh số liên tục, tất cả các câu trả lời khác đều giống nhau.
gniourf_gniourf

Những câu trả lời khác giả định đánh số liên tục? Tôi chỉ tìm thấy bình luận của Ulrich Schwarz và không có câu trả lời như vậy.
manatwork

5

Chỉ cần với bash, bạn có thể làm:

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

Mẫu ./*.jpgsẽ được thay thế bằng một danh sách tên tệp được sắp xếp theo thứ tự bảng chữ cái như được nêu bởi bash man, vì vậy nó phải phù hợp với mục đích của bạn.


Trong bash, ba dòng của bạn bên trong forvòng lặp có thể được thay thế chỉ bằng dòng này : (((++n)%4)) || cp "$file" selected/. ;-). Vấn đề là bạn đang cptìm kiếm một tệp không thực sự hiệu quả.
gniourf_gniourf

1

Nếu bạn đã rubycài đặt, bạn có thể sử dụng một lớp lót sau đây. Lưu ý rằng nó giả định rằng thư mục được chọn tồn tại.

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

Nó lấy một danh sách tất cả các tệp có phần mở rộng .jpg trong thư mục hiện tại và cắt nó thành danh sách bốn phần tử và sao chép phần tử đầu tiên từ mỗi danh sách đó vào thư mục được chọn trong thư mục hiện tại.


1

Nếu bạn biết bạn sẽ không có dòng mới trong tên tệp của mình, bạn có thể sử dụng:

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

@Gilles: cảm ơn vì đã chỉnh sửa. Tôi đã loại bỏ biến tệp trong 3 lần đọc, vì tôi muốn chỉ ra rằng chúng không cần thiết.
jfg956

0

Bạn có thể sử dụng trình quản lý tệp GUI và thay đổi kích thước đường viền của cửa sổ cho đến khi cứ 5 tệp chiếm một hàng, sau đó sử dụng chuột để chọn cột đầu tiên ...


-1

Nhìn vào stackoverflow.com/q/4553751/789593 cung cấp giải pháp sao chép từng giây như @NN đã đề cập, một giải pháp rất đơn giản sẽ là:

  • Xóa tệp đầu tiên khỏi thư mục bắt đầu
  • Sao chép từng giây từ thư mục bắt đầu sang thư mục trung gian
  • Sao chép từng giây từ thư mục trung gian vào thư mục cuối cùng
  • Thêm tệp đầu tiên theo cách thủ công

Nó có thể không hiệu quả lắm vì nó đòi hỏi một bước sao chép thêm nên nó rất dễ thực hiện.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.