Tôi có một thư mục có tên /home/user/temps
487 thư mục. Trong mỗi thư mục tôi có một tập tin gọi là thumb.png.
Tôi muốn sao chép tất cả các tệp có tên thumb.png vào một thư mục riêng và đổi tên chúng dựa trên thư mục mà chúng đến.
Tôi có một thư mục có tên /home/user/temps
487 thư mục. Trong mỗi thư mục tôi có một tập tin gọi là thumb.png.
Tôi muốn sao chép tất cả các tệp có tên thumb.png vào một thư mục riêng và đổi tên chúng dựa trên thư mục mà chúng đến.
Câu trả lời:
Ở đây bạn đi:
for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;
biên tập:
Nhân tiện, sự khôn ngoan kinh điển là việc sử dụng find
cho điều này là một ý tưởng tồi - chỉ đơn giản là sử dụng mở rộng vỏ là đáng tin cậy hơn nhiều. Ngoài ra, điều này giả định bash
, nhưng tôi cho rằng đó là một giả định an toàn :)
chỉnh sửa 2:
Để rõ ràng, tôi sẽ phá vỡ nó:
# 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;
chi tiết về ${var/Pattern/Replacement}
cấu trúc có thể được tìm thấy ở đây .
các trích dẫn trong cp
dòng rất quan trọng để xử lý các khoảng trắng và dòng mới, v.v. trong tên tệp.
new_file/\/thumb
gì?
${VARIABLE/PATTTERN/REPLACEMENT}
tạo ra giá trị của VARIABLE
nhưng với mẫu thay thế bằng văn bản thay thế. Ở đây mô hình là /thumb
( /
nhu cầu được thoát ra sao cho nó không giống như thế ${new_file//PATTERN/REPLACEMENT}
, điều này làm cho nó thay thế toàn cầu thay vì thay thế lần đầu tiên) và văn bản thay thế trống rỗng.
/home/user/temps
, điều này không rõ ràng trong câu hỏi. Nếu họ không, bạn cần tìm hoặc **
.
Điều này làm việc cho các thư mục con sâu tùy ý:
$ 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'
Phần xen kẽ là phần mở rộng tham số ${NAME//\//_}
. Nó có nội dung NAME
và thay thế mọi lần xuất hiện của /
với _
.
Lưu ý: kết quả phụ thuộc vào thư mục làm việc và tham số đường dẫn cần tìm. Tôi đã thực thi lệnh từ thư mục mẹ của temps. Thay thế cp
bằng echo
để thử nghiệm.
Mã trợ giúp ngắn:
#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}"
#
mv "$1" ../tmp/"${1//\//_}"
hãy đặt tên cho nó là 'deslash.sh' và làm cho nó có thể thực thi được. Gọi nó với:
find -type f -name thumb.png -exec ./deslash.sh {} ";"
Nó sẽ thất bại, nếu một vụ va chạm tồn tại
a/b/thumb.png # and
a_b/thumb.png
nhưng đó là điều không thể tránh khỏi.
Thử đi
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
Biên tập
Tôi đã thêm trích dẫn trong trường hợp bất kỳ tên dir nào của bạn có ký tự khoảng trắng được nhúng trong chúng.
Ngoài ra tôi đã thay đổi điều này để nó sẽ chỉ in ra các lệnh sẽ được thực thi. Kiểm tra đầu ra của tập lệnh để đảm bảo tất cả các tên tệp / đường dẫn trông phù hợp. Khi bạn chắc chắn không có vấn đề gì với các lệnh sẽ được thực thi, hãy xóa echo
.
mv -i ./A A/thumb.png ../tmp/.png
- tất cả các tệp kết thúc bằng ../tmp/.png (../tmp là thư mục tiêu của tôi).
find -type d
và xem đầu ra. Điều đó có nhận được tất cả các thư mục bạn mong đợi? Nó nên, nếu không, xin vui lòng thêm một số đầu ra để hiển thị vấn đề. Chúc may mắn.
read dir
thực hiện phân tách từ và lấy, từ một thư mục a\nb
a và b làm hai trường hợp mà không có mặt nạ nào có thể giải quyết.
Để sao chép, bạn cần lệnh cp và đổi tên cho linux cũng giống như di chuyển tệp, vì vậy bạn phải thực hiện bằng lệnh mv . Trong Linux, bạn luôn phải chỉ định toàn bộ đường dẫn, từ nguồn, nếu bạn đang ở trong một thư mục khác, và đến thư mục đích, tất nhiên. Tôi sẽ là một cái gì đó như thế này, để sao chép:
cp /source_path/file /destination_path/
hoặc đổi tên hoặc di chuyển
mv /source_path/old_file /destination_path/new_name_file