mv: could stat Không có tập tin hoặc thư mục như vậy trong shell script


16

Tôi đã viết một tập lệnh để di chuyển một số tệp từ một thư mục sang thư mục khác nhưng tôi gặp lỗi sau, tôi đã kiểm tra 2 thư mục và thông báo cho 1 thư mục có các tệp đó và một tệp khác không có tệp đó, nhưng tại sao tất cả chúng đều hiển thị "mv không thể thống kê Không có tập tin hoặc thư mục như vậy "

    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/194.42.17.124_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/195.113.161.13_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.199.61.205_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/212.51.218.235_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/213.73.40.105_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/41.225.7.4_tcp.folder/data/*': No such file or directory
    mv: cannot stat `/home/esolve/project/capture/tcp_50x50/dest_folder/83.230.127.122_tcp.folder/data/*': No such file or directory
    [esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/194.199.68.165_tcp.folder/
    [esolve@kitty tcp_50x50]$ ls /home/wgong/project/capture/tcp_50x50/dest_folder/203.159.127.3_tcp.folder/data/
    129.88.70.226   132.187.230.1    138.96.116.22   155.185.54.250   192.38.109.144  193.136.227.163  193.175.135.61  195.113.161.13  83.230.127.122
    130.104.72.200  132.227.62.122   147.83.29.232   156.17.10.52     192.42.43.22    193.137.173.218  193.205.215.74  212.199.61.205
    131.130.69.164  132.252.152.194  148.81.140.193  157.181.175.249  192.43.193.71   193.144.21.131   193.226.19.30   212.51.218.235
    131.188.44.102  134.151.255.180  152.66.245.162  160.78.253.31    193.1.170.136   193.145.46.243   194.199.68.165  213.73.40.105
    131.254.208.10  138.48.3.203     152.81.47.4     192.114.4.3      193.136.166.56  193.166.160.98   194.42.17.124   41.225.7.4

kịch bản là:

    list=`ls dest_folder`
    cd dest_folder
    cwd=`pwd`
    for folder in $list;do
            mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}
    done

Tôi chạy nó vào /home/esolve/project/capture/tcp_50x50/


1
Vui lòng hiển thị các phần có liên quan của kịch bản.
Mat

Tôi đã cập nhật câu hỏi của tôi và thêm kịch bản, cảm ơn!
sương mù

Bạn có cần phải thêm một -rđến mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}?
ProfessionalAm Nghiệp dư

không có -rlựa chọn nào chomv
Misteryes

Câu trả lời:


24
mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}

Các trích dẫn ( ') ở đó ngăn chặn vỏ thực hiện Globing. Việc *này đang được truyền theo nghĩa đen cho mvlệnh, không thành công vì nó không tìm thấy các tệp được gọi *trong các thư mục được chỉ định.

Thay đổi điều này thành:

mv "${cwd}/${folder}/data"/* "${cwd}/${folder}"

(Dấu ngoặc kép để ngăn sự cố nếu bạn có tên thư mục có khoảng trắng trong đó. Bên *ngoài dấu ngoặc kép.)

Bạn vẫn sẽ nhận được các lỗi cho các thư mục trống mặc dù. (Cùng một loại lý do: nếu tệp không tìm thấy sự trùng khớp cho mẫu, nó sẽ tự chuyển mẫu đó làm đối số cho lệnh.)


Dấu ngoặc kép có ý nghĩa, nhưng tại sao tôi cần phải đặt *bên ngoài dấu ngoặc kép?
Đánh bạc Sibbs

Nếu bạn muốn nó được mở rộng, bạn cần nó bên ngoài @SibbsGambled
Mat

8

Có một số vấn đề với mã của bạn:

list=`ls dest_folder`

Bạn đang lưu trữ đầu ra của ls mà không có các ký tự dòng mới vào $list. lsxuất ra danh sách các tên tệp được phân tách bằng các ký tự dòng mới. newlinelà một ký tự hợp lệ như bất kỳ trong một tên tệp, do đó đầu ra không thể được sử dụng một cách đáng tin cậy. Chẳng hạn, lsđầu ra cho một thư mục chứa abgiống như đầu ra cho một thư mục chứa một tệp được gọi a<newline>b.

 cd dest_folder

Bạn không kiểm tra sự thất bại của lệnh đó. Nói chung, bạn nên kiểm tra trạng thái thoát của các lệnh, nhưng điều đó đặc biệt đúng cd, bởi vì các lệnh còn lại cho rằng bạn đang ở trong thư mục mới đó và điều đó có thể gây ra hậu quả nghiêm trọng khi bạn không.

cwd=`pwd`

Các shell POSIX đã duy trì đường dẫn (một) đến thư mục hiện tại trong $PWDbiến, vì vậy bạn không cần sử dụng pwdở đây (đặc biệt trong trường hợp chung vì thay thế lệnh sẽ xóa các ký tự dòng mới khỏi đường dẫn). Ngoài ra, mvchấp nhận các đường dẫn tương đối để bạn không cần xây dựng đường dẫn tuyệt đối.

for folder in $list;do

Để lại một biến không được trích dẫn là toán tử split + global trong shell. Nghĩa là, nội dung của biến được phân tách (trên các dấu phân cách được đề cập trong $IFScác quy tắc đặc biệt cho các khoảng trắng) và mỗi phần tử dẫn đến việc phân tách đó được tìm kiếm các ký tự đại diện để chúng có thể được mở rộng vào danh sách các tệp phù hợp.

Ở đây, bạn thực sự muốn chia tách, nhưng chỉ trên các ký tự dòng mới và bạn không muốn toàn cầu hóa, vì vậy bạn cần phải vô hiệu hóa nó:

 IFS='
 '; set -f
 for folder in $list
   mv ${cwd}/${folder}'/data/*' ${cwd}/${folder}

Một lần nữa, để lại một biến không được trích dẫn là toán tử split + global . Ở đây, bạn không muốn, vì vậy bạn cần trích dẫn các biến đó.

Như đã đề cập, ký tự đại diện chỉ được mở rộng khi không được trích dẫn, để bạn cần chuyển nó *ra khỏi dấu ngoặc kép. Nếu bạn đã vô hiệu hóa toàn cầu sớm hơn set -f, bạn cần khôi phục nó set +ftrước khi gọi lệnh đó.

Một cách tốt hơn để viết nó sẽ là:

cd dest_folder &&
  for folder in */;do
    mv -- "${folder}data/"* "$folder"
  done

Một vài lưu ý mặc dù:

  • Điều đó sẽ loại trừ các thư mục ẩn và sẽ không di chuyển các tệp ẩn khỏi data thư mục.
  • Chúng tôi không kiểm tra các tệp bị ghi đè trong quy trình (bạn có thể muốn thêm -i tùy chọn này mv).
  • Bằng cách sử dụng */, chúng tôi lặp qua các thư mục , nhưng điều đó bao gồm các liên kết tượng trưng đến các thư mục. Nếu bạn không muốn, bạn cần thêm một [ -L "${folder%/}" ] && continuevòng lặp.
  • Nếu không có thư mục không bị ẩn trong đó */sẽ mở rộng sang chính nó, vì vậy bạn sẽ nhận được và thông báo lỗi khi mvnói rằng nó không thể tìm thấy một tệp được gọi */data/*. Tương tự, nếu không có tệp không bị ẩn trong bất kỳ thư mục nào, bạn sẽ nhận được thông báo lỗi that-folder/data/*không tồn tại.
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.