Di chuyển một tập tin và thay thế nó bằng một liên kết tượng trưng


16

Ai đó có thể cho tôi một lệnh sẽ:

  • di chuyển một tập tin về phía một thư mục mới
  • và để lại một liên kết tượng trưng ở vị trí cũ của nó đối với vị trí mới

Câu trả lời:


18

mvdi chuyển một tệp và ln -stạo một liên kết tượng trưng, ​​do đó, tác vụ cơ bản được hoàn thành bởi một tập lệnh thực thi hai lệnh này:

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

Có một vài hãy cẩn thận. Nếu đối số thứ hai là một thư mục, thì mvsẽ di chuyển tệp vào thư mục đó, nhưng ln -ssẽ tạo một liên kết đến thư mục chứ không phải là tệp đã di chuyển.

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

Một cảnh báo khác là đối số đầu tiên ln -slà văn bản chính xác của liên kết tượng trưng. Nó liên quan đến vị trí của mục tiêu, không liên quan đến thư mục nơi lệnh được thực thi. Nếu vị trí ban đầu không có trong thư mục hiện tại và mục tiêu không được thể hiện bằng một đường dẫn tuyệt đối, liên kết sẽ không chính xác. Trong trường hợp này, đường dẫn cần phải được viết lại. Trong trường hợp này, tôi sẽ tạo một liên kết tuyệt đối (một liên kết tương đối sẽ tốt hơn, nhưng khó hơn để có được quyền). Kịch bản này giả định rằng bạn không có tên tệp kết thúc bằng ký tự dòng mới.

#!/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"

Nếu bạn có nhiều tệp, xử lý chúng trong một vòng lặp.

#!/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
Cảm ơn Gilles, cho kịch bản và những lời giải thích. Tôi sẽ cố gắng để hiểu điều đó!
Yo B.

Điều này nên được đánh dấu là câu trả lời đúng
Sridhar Sarnobat

Để làm cho câu trả lời này trở nên tuyệt vời hơn nữa, rsync --remove-source-filescó thể nhiều thông tin hơn cho người dùng đang di chuyển một tệp lớn ra khỏi đĩa có thể mất một thời gian.
Sridhar Sarnobat

Tôi nghĩ bạn nên gọi sh với -e để nó bị lỗi, ví dụ nếu bạn dừng lệnh mv vì một tệp đã tồn tại
Alex

2

Đặt tệp này trong tệp .sh và làm cho nó có thể thực thi được ( chmod +x filename):

#!/bin/bash

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

Ví dụ sử dụng:

./test.sh asdf otherdir/asdf

Lưu ý rằng điều này không kiểm tra an toàn, vv Tùy thuộc vào mức độ phức tạp của nhiệm vụ của bạn, điều này có thể là đủ.


Cảm ơn Matthew, điều này hoạt động hoàn hảo khi áp dụng trên một tập tin. Nhưng bạn có thể giúp tôi khái quát điều này đến hai thư mục như thế này : ./test.sh .mozila/firefox/zotero/*/*.pdf MyBbliography/*.pdf. Điều *này dường như không làm việc với của bạn test.sh. Bạn đã có một cách giải quyết? Thx
Yo B.

2
Tập lệnh của @kadok MatthewRock chỉ hoạt động cho một tệp duy nhất và mục tiêu phải là một đường dẫn tuyệt đối nếu không thì nguồn phải nằm trong thư mục hiện tại.
Gilles 'SO- ngừng trở nên xấu xa'

Ngoài ra, nó sẽ không hoạt động nếu $ 1 là một tệp nhưng $ 2 là một thư mục.
Sridhar Sarnobat

0

Tôi thường sử dụng chức năng một dòng này:

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

Cách sử dụng tương tự như mv hoặc cp:

ml old_file target_dir/new_file_name

Phá vỡ nó:

  • mkdir -p "$(dirname "$1")" - tạo thư mục đích nếu nó chưa tồn tại
    • dirname "$1" - lấy thành phần thư mục của đường dẫn (tước tên tệp)
  • rsync -aP --no-links "$1" "$2"- sao chép tập tin đến đích. Thay thế điều này bằng mv "$1" "$2"nếu cả hai tệp nằm trên cùng một hệ thống tệp để có hiệu suất tốt hơn.
    • -a- bảo vệ quyền sở hữu và tất cả các quyền khác. Bạn có thể điều chỉnh điều này để chỉ bảo quản các thành phần bạn muốn.
    • -P - cho thấy sự tiến bộ.
    • --no-links - không sao chép liên kết - điều này có nghĩa là bạn có thể chạy lệnh này bao nhiêu lần tùy ý trên cùng một tệp và bạn sẽ không bao giờ bị mất tệp của mình bằng cách vô tình ghi đè tệp đích của bạn bằng chính liên kết đó.
  • ln -sf "$2" "$1" - ghi đè tệp cũ bằng liên kết tượng trưng đến tệp mới
    • -s - sử dụng các liên kết tượng trưng
    • -f - ghi đè tập tin cũ
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.