ファイルを移動し、シンボリックリンクに置き換えます


16

誰かが私にコマンドを与えることができます:

  • ファイルを新しいディレクトリに移動します
  • 古い場所に新しい場所へのシンボリックリンクを残します

回答:


18

mvファイルを移動しln -s、シンボリックリンクを作成します。したがって、基本的なタスクは、次の2つのコマンドを実行するスクリプトによって実行されます。

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

いくつかの注意事項があります。2番目の引数がディレクトリの場合、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"

もう1つの注意点は、最初の引数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。私はそれを理解しようとします!
ヨB.

これは、正しい答えとしてマークされなければならない
シュリダールSarnobat

この答えをさらに素晴らしいrsync --remove-source-filesものにするためには、時間がかかるディスクから大きなファイルを移動するユーザーにとって、より有益な情報になるかもしれません。
シュリダールSarnobat

私はそれがエラーに壊れるようにファイルがすでに存在しているので、あなたがMVコマンドを停止する場合は、たとえば、-eとSHを呼ぶべきだと思います
アレックス・

2

これを.shファイルに入れて実行可能にします(chmod +x filename):

#!/bin/bash

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

使用例:

./test.sh asdf otherdir/asdf

これは安全チェックなどを行わないことに注意してください。タスクの複雑さによっては、これで十分な場合があります。


Matthewに感謝します。これは1つのファイルに適用すると完全に機能します。しかし、あなたは私がこのような二つのディレクトリにこれを一般化することができます: ./test.sh .mozila/firefox/zotero/*/*.pdf MyBbliography/*.pdf*あなたに動作していないようですtest.sh。回避策はありますか?Thx
ヨB.

2
@kadok MatthewRockのスクリプトは1つのファイルに対してのみ機能し、ターゲットは絶対パスであるか、ソースが現在のディレクトリにある必要があります。
ジル「SO-悪であるのをやめる」

また、$ 1がファイルで$ 2がディレクトリの場合は機能しません。
シュリダールSarnobat

0

通常、次の1行関数を使用します。

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" -古いファイルを新しいファイルへのシンボリックリンクで上書きします
    • -s -シンボリックリンクを使用する
    • -f -古いファイルを上書きする
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.