ย้ายไฟล์และแทนที่ด้วย symlink


16

ใครสามารถให้คำสั่งที่จะ:

  • ย้ายไฟล์ไปยังไดเรกทอรีใหม่
  • และปล่อยให้ symlink อยู่ในตำแหน่งเดิมไปยังตำแหน่งใหม่

คำตอบ:


19

mvย้ายไฟล์และln -sสร้างลิงก์สัญลักษณ์เพื่อให้งานพื้นฐานสำเร็จโดยสคริปต์ที่ดำเนินการกับสองคำสั่งนี้:

#!/bin/sh
mv -- "$1" "$2"
ln -s -- "$2" "$1"

มีข้อแม้อยู่เล็กน้อย หากอาร์กิวเมนต์ที่สองคือไดเรกทอรีดังนั้นmvจะย้ายไฟล์ไปยังไดเรกทอรีนั้น แต่ln -sจะสร้างลิงก์ไปยังไดเรกทอรีแทนที่จะไปยังไฟล์ที่ถูกย้าย

#!/bin/sh
set -e
original="$1" target="$2"
if [ -d "$target" ]; then
  target="$target/${original##*/}"
fi
mv -- "$original" "$target"
ln -s -- "$target" "$original"

ข้อแม้อื่นก็คืออาร์กิวเมนต์แรกln -sคือข้อความที่ถูกต้องของลิงก์สัญลักษณ์ มันสัมพันธ์กับตำแหน่งของเป้าหมายไม่ใช่ไปยังไดเร็กทอรีที่คำสั่งถูกเรียกใช้งาน หากตำแหน่งดั้งเดิมไม่ได้อยู่ในไดเรกทอรีปัจจุบันและเป้าหมายไม่ได้แสดงโดยพา ธ สัมบูรณ์ลิงก์จะไม่ถูกต้อง ในกรณีนี้จำเป็นต้องเขียนเส้นทางใหม่ ในกรณีนี้ฉันจะสร้างลิงค์สัมบูรณ์ (ลิงก์ที่เกี่ยวข้องน่าจะดีกว่า แต่จะยากกว่านี้) สคริปต์นี้อนุมานว่าคุณไม่มีชื่อไฟล์ที่ลงท้ายด้วยอักขระขึ้นบรรทัดใหม่

#!/bin/sh
set -e
original="$1" target="$2"
if [ -d "$target" ]; then
  target="$target/${original##*/}"
fi
mv -- "$original" "$target"
case "$original" in
  */*)
    case "$target" in
      /*) :;;
      *) target="$(cd -- "$(dirname -- "$target")" && pwd)/${target##*/}"
    esac
esac
ln -s -- "$target" "$original"

หากคุณมีหลายไฟล์ให้ประมวลผลในลูป

#!/bin/sh
while [ $# -gt 1 ]; do
  eval "target=\${$#}"
  original="$1"
  if [ -d "$target" ]; then
    target="$target/${original##*/}"
  fi
  mv -- "$original" "$target"
  case "$original" in
    */*)
      case "$target" in
        /*) :;;
        *) target="$(cd -- "$(dirname -- "$target")" && pwd)/${target##*/}"
      esac
  esac
  ln -s -- "$target" "$original"
  shift
done

1
ขอบคุณ Gilles สำหรับสคริปต์และคำอธิบาย ฉันจะพยายามเข้าใจสิ่งนั้น!
Yo B.

ควรทำเครื่องหมายเป็นคำตอบที่ถูกต้อง
Sridhar Sarnobat

เพื่อให้คำตอบนี้ยอดเยี่ยมยิ่งขึ้นrsync --remove-source-filesอาจเป็นข้อมูลสำหรับผู้ใช้ที่กำลังย้ายไฟล์ขนาดใหญ่ออกจากดิสก์ซึ่งอาจใช้เวลาสักครู่
Sridhar Sarnobat

ฉันคิดว่าคุณควรจะเรียก sh ด้วย -e ดังนั้นมันจึงหยุดข้อผิดพลาดตัวอย่างเช่นถ้าคุณหยุดคำสั่ง mv เพราะไฟล์มีอยู่แล้ว
Alex

2

ใส่สิ่งนี้ในไฟล์. sh และทำให้มันปฏิบัติ ( chmod +x filename):

#!/bin/bash

mv "$1" "$2"
ln -s "$2" "$1"

ตัวอย่างการใช้งาน:

./test.sh asdf otherdir/asdf

โปรดทราบว่านี่ไม่ใช่การตรวจสอบความปลอดภัย ฯลฯ งานของคุณอาจซับซ้อนเพียงพอ


ขอบคุณ Matthew มันใช้งานได้ดีเมื่อใช้กับไฟล์เดียว แต่คุณสามารถช่วยฉัน generalising ./test.sh .mozila/firefox/zotero/*/*.pdf MyBbliography/*.pdfนี้สองไดเรกทอรีเช่นนี้ ดูเหมือนจะไม่ได้ร่วมงานกับคุณ* test.shคุณมีวิธีแก้ปัญหาหรือไม่? ขอบคุณ
Yo B.

2
สคริปต์ของ @kadok MatthewRock ใช้ได้กับไฟล์เดียวเท่านั้นและเป้าหมายต้องเป็นพา ธ สัมบูรณ์ไม่เช่นนั้นแหล่งข้อมูลต้องอยู่ในไดเรกทอรีปัจจุบัน
Gilles 'หยุดความชั่วร้าย'

นอกจากนี้มันจะไม่ทำงานหาก $ 1 เป็นไฟล์ แต่ $ 2 เป็นไดเรกทอรี
Sridhar Sarnobat

0

ฉันมักจะใช้ฟังก์ชั่นหนึ่งบรรทัดนี้:

function ml() { mkdir -p "$(dirname "$1")" && rsync -aP --no-links "$1" "$2" && ln -sf "$2" "$1" }

การใช้งานคล้ายกับ mv หรือ cp:

ml old_file target_dir/new_file_name

ทำลายมันลง:

  • mkdir -p "$(dirname "$1")" - สร้างไดเรกทอรีปลายทางหากยังไม่มีอยู่
    • dirname "$1" - รับองค์ประกอบไดเรกทอรีของเส้นทาง (ตัดชื่อไฟล์)
  • rsync -aP --no-links "$1" "$2"- คัดลอกไฟล์ไปยังปลายทาง แทนที่สิ่งนี้ด้วยmv "$1" "$2"หากไฟล์ทั้งสองอยู่ในระบบไฟล์เดียวกันเพื่อประสิทธิภาพที่ดีขึ้น
    • -a- สงวนสิทธิ์การเป็นเจ้าของและสิทธิ์อื่น ๆ ทั้งหมด คุณสามารถปรับแต่งสิ่งนี้เพื่อรักษาองค์ประกอบที่คุณต้องการเท่านั้น
    • -P - แสดงความคืบหน้า
    • --no-links - อย่าคัดลอกลิงก์ - ซึ่งหมายความว่าคุณสามารถเรียกใช้คำสั่งนี้ได้หลายครั้งตามที่คุณต้องการในไฟล์เดียวกันและคุณจะไม่สูญเสียไฟล์ของคุณโดยการเขียนทับไฟล์ปลายทางด้วยการเชื่อมโยงไปยังตัวเองโดยไม่ตั้งใจ
  • ln -sf "$2" "$1" - เขียนทับไฟล์เก่าด้วย symlink ไปที่ไฟล์ใหม่
    • -s - ใช้ลิงก์สัญลักษณ์
    • -f - เขียนทับไฟล์เก่า
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.