mv: ไม่สามารถสถิติไม่มีไฟล์หรือไดเรกทอรีดังกล่าวในเชลล์สคริปต์


16

ฉันเขียนสคริปต์เพื่อย้ายไฟล์บางไฟล์ในรูปแบบโฟลเดอร์หนึ่งไปยังอีกโฟลเดอร์หนึ่ง แต่ฉันพบข้อผิดพลาดต่อไปนี้ฉันตรวจสอบ 2 โฟลเดอร์และแจ้งให้ทราบสำหรับ 1 โฟลเดอร์มีไฟล์ดังกล่าวและอีกไฟล์หนึ่งไม่มีไฟล์ดังกล่าว แต่ทำไมทุกไฟล์แสดง "mv stat ไม่สามารถไม่มีไฟล์หรือไดเรกทอรีดังกล่าว "

    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

สคริปต์คือ:

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

ฉันวิ่งเข้าไป /home/esolve/project/capture/tcp_50x50/


1
กรุณาแสดงส่วนที่เกี่ยวข้องของสคริปต์
จ้า

ฉันอัพเดตคำถามและเพิ่มสคริปต์แล้วขอบคุณ!
misteryes

คุณต้องเพิ่ม-rไปmv ${cwd}/${folder}'/data/*' ${cwd}/${folder}?
ProfessionalAmateur

ไม่มี-rตัวเลือกสำหรับmv
misteryes

คำตอบ:


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

เครื่องหมายคำพูด ( ') มีการป้องกันไม่ให้เปลือกทำแบบกลม *จะถูกส่งผ่านตัวอักษรกับmvคำสั่งที่ล้มเหลวเพราะมันไม่ได้เรียกว่าหาไฟล์*ในไดเรกทอรีที่ระบุ

เปลี่ยนเป็น:

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

(เครื่องหมายคำพูดคู่เพื่อป้องกันปัญหาหากคุณมีชื่อไดเรกทอรีที่มีช่องว่างอยู่*นอกเครื่องหมายคำพูด)

คุณจะยังคงได้รับข้อผิดพลาดสำหรับไดเรกทอรีว่างแม้ว่า (เหตุผลประเภทเดียวกัน: หากไฟล์ไม่พบรายการที่ตรงกันสำหรับรูปแบบไฟล์จะส่งรูปแบบตัวเองเป็นอาร์กิวเมนต์ไปยังคำสั่ง)


การเสนอราคาซ้ำกันนั้นสมเหตุสมผล แต่ทำไมฉันต้องใส่*เครื่องหมายอัญประกาศ
การพนัน Sibbs

หากคุณต้องการให้มันขยายคุณต้องการนอก @SibbsGambling
Mat

8

รหัสของคุณมีปัญหาหลายประการ:

list=`ls dest_folder`

คุณเก็บการส่งออกของโดยไม่ต้องต่อท้ายตัวอักษรบรรทัดใหม่เข้าไปls ส่งออกรายการชื่อไฟล์ที่คั่นด้วยอักขระบรรทัดใหม่ มีความถูกต้องของตัวอักขระในชื่อไฟล์ดังนั้นจึงไม่สามารถใช้เอาต์พุตได้อย่างน่าเชื่อถือ สำหรับกรณีที่การส่งออกในไดเรกทอรีที่มีและเป็นเช่นเดียวกับหนึ่งในไดเรกทอรีที่มีไฟล์เดียวที่เรียกว่า$listlsnewlinelsaba<newline>b

 cd dest_folder

คุณไม่ได้ตรวจสอบความล้มเหลวของคำสั่งนั้น โดยทั่วไปคุณควรตรวจสอบสถานะการออกคำสั่ง แต่โดยเฉพาะอย่างยิ่งcdเพราะส่วนที่เหลือของคำสั่งถือว่าคุณอยู่ในไดเรกทอรีใหม่นั้นและอาจมีผลกระทบอย่างมากเมื่อคุณไม่ได้

cwd=`pwd`

POSIX เชลล์รักษาเส้นทาง (หนึ่ง) ไปยังไดเรกทอรีปัจจุบันใน$PWDตัวแปรดังนั้นคุณไม่จำเป็นต้องใช้pwdที่นี่ (โดยเฉพาะในกรณีทั่วไปเนื่องจากการแทนที่คำสั่งจะลบอักขระบรรทัดใหม่ต่อท้ายออกจากเส้นทาง) นอกจากนี้ยังmvยอมรับเส้นทางที่เกี่ยวข้องดังนั้นคุณไม่จำเป็นต้องสร้างเส้นทางที่แน่นอน

for folder in $list;do

การปล่อยตัวแปรที่ไม่มีเครื่องหมายคือตัวแยก + globในเชลล์ นั่นคือเนื้อหาของตัวแปรจะแยก (ตามตัวคั่นที่กล่าวถึง$IFSด้วยกฎพิเศษสำหรับช่องว่าง) และแต่ละองค์ประกอบที่เป็นผลมาจากการแยกนั้นจะค้นหาอักขระตัวแทนเพื่อให้สามารถขยายไปยังรายการของไฟล์ที่ตรงกัน

ที่นี่คุณต้องการแยก แต่เฉพาะอักขระขึ้นบรรทัดใหม่และคุณไม่ต้องการให้กลมกลืนดังนั้นคุณต้องปิดการใช้งาน:

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

อีกครั้งที่ออกจากตัวแปร unquoted เป็นที่แยก + globผู้ประกอบการ ที่นี่คุณไม่ต้องการดังนั้นคุณต้องอ้างอิงตัวแปรเหล่านั้น

ดังที่ได้กล่าวไปแล้วไวลด์การ์ดจะถูกขยายเมื่อไม่ได้ยกมาเพื่อที่คุณจะต้องย้าย*ออกจากคำพูด หากคุณปิดการใช้งานก่อนหน้านี้ด้วยset -fคุณจะต้องกลับสู่สถานะเดิมset +fก่อนที่จะเรียกคำสั่งนั้น

วิธีที่ดีกว่าในการเขียน:

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

หมายเหตุเล็กน้อยที่:

  • ซึ่งจะยกเว้นโฟลเดอร์ที่ซ่อนอยู่และจะไม่ย้ายไฟล์ที่ซ่อนอยู่จากdataโฟลเดอร์
  • เราไม่ได้ตรวจสอบไฟล์ที่ถูกแทนที่ในกระบวนการ (คุณอาจต้องการเพิ่ม-iตัวเลือกmv)
  • โดยการใช้*/งานเราจะทำการวนซ้ำไดเรกทอรีต่างๆเท่านั้น แต่นั่นรวมถึงลิงก์สัญลักษณ์ไปยังไดเรกทอรีด้วย หากคุณไม่ต้องการคุณจะต้องเพิ่ม[ -L "${folder%/}" ] && continueวงใน
  • ถ้าไม่มีโฟลเดอร์ที่ไม่ใช่ที่ซ่อนอยู่ในนั้น*/จะขยายไปยังตัวเองเพื่อให้คุณจะได้รับและข้อผิดพลาดจากการบอกว่ามันไม่สามารถหาไฟล์ที่เรียกว่าmv */data/*ในทำนองเดียวกันหากไม่มีไฟล์ที่ไม่ซ่อนอยู่ในโฟลเดอร์ใด ๆ คุณจะได้รับข้อความแสดงข้อผิดพลาดที่that-folder/data/*ไม่มีอยู่
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.