ディレクトリ内のファイルをリンクするスクリプトの助けが必要です。

ディレクトリ内のファイルをリンクするスクリプトの助けが必要です。

私はbashスクリプトに初めてアクセスし、ユーザー入力を受け取り、ディレクトリ内のすべてのファイルを別のディレクトリにハードリンクするスクリプトを作成したいと思います。これまで私はこれを持っています:


read -p "What directory do you want to link? " dir

items=$(ls -m $dir -Q | tr -d '\n'' ')

read -p "Where do you want to link the files? " outdir

echo "Linking files: $items to: $outdir"

read -p "Continue? (y/N) " confirmation

if [ $confirmation == "y" ] || [ $confirmation == "Y" ]; then
    ln $dir/{$items} $outdir
else
    kill -SIGTERM $$
fi

私が入力し/home/ethan/test/home/ethan/test2取得するときln: failed to access '/home/ethan/test/{"test1","test2"}': No such file or directory

また、その内容は私がArchに持っている/home/ethan/test2つのファイルです。test1test2

これを行うには、何を変更する必要があるのか​​を理解するのに役立つ人がいますか?ありがとうございます。

答え1

このような短いユーティリティスクリプトにはお勧めしますいいえインタラクティブにしてください。ユーザーは、説明した方法でコピーしたいディレクトリを正確に知っている可能性があり、ユーザーがコマンドラインでタブの完成および/またはファイル名のグロービングを使用できるようにすると、次のように入力するのと同じ結果が得られる可能性が高くなります。メモリから取得したパラメータと比較すると、パラメータは正確です。

また、私はls他のものを使用しませんファイルリストを見るlsファイル名を読み取るためにスクリプトで使用しないでください。ファイル名グロービングパターンを使用するのが最善です。これについては他のQ&Aで詳しく説明します。なぜ`ls`を解析しないのですか*(そしてどうすればいいですか?)

スクリプトを終了するには、最後まで実行するか、を使用しますexitkillまた、通常、単語の区切りや不要なファイル名のグロービングを防ぐために、すべての変数拡張子を二重引用符で囲みます。いつ二重引用符が必要ですか?)。

中かっこ拡張内でシェル変数を使用しようとすると、特定のエラーが発生します。これは不可能ですbash(たとえば、中かっこと変数拡張を1行に結合)。

ユーザーが名前がダッシュで始まるディレクトリを使用しようとすると、追加の問題が発生します。


ls出力を使用して、中括弧の拡張に使用される一種のリスト(カンマ、改行、その他の文字を含むファイル名を抑制する)に結合するのではなく、関数またはシェルスクリプトをシェルにラップするオプションをrsync使用します。--link-dest利便性:

#!/bin/sh -

# The two expected arguments are
#     1. an existing source directory, and
#     2. a possibly existing destination directory

if [ ! -d "$1" ]; then
    printf 'Not a directory: %s\n' "$1" >&2
    exit 1
fi

if [ -e "$2" ] && [ ! -d "$2" ]; then
    printf 'Not a directory: %s\n' "$2" >&2
    exit 1
fi

rsync -a --link-dest="$(readlink -f -- "$1")" -- "$1/" "$2"

まず、ユーザーが有効なパラメータを提供していることを確認する必要があります。このスクリプトの場合、これは最初の引数(ソース)が既存のディレクトリでなければならず、2番目の引数(ターゲット)が存在しないか、ディレクトリである必要があることを意味します。

オプションとともに、ソースディレクトリの絶対パスが使用されていることをreadlink -f確認するために使用します。それ以外の場合は、ターゲットディレクトリパスに対する相対パスを解釈します。このユーティリティは標準ではありませんが、一般的です。--link-destrsyncreadlink

この方法では、rsyncソースディレクトリがターゲットディレクトリパスで繰り返し生成され(ソースとターゲットが同じファイルシステムにある場合)、ディレクトリ以外のファイルがハードリンクされます。ソースパスとターゲットパスが異なるファイルシステムにある場合、ソースディレクトリパスは再帰的です。コピー代わりにハードリンクは作成されません。

呼び出しのソースパラメータの末尾にスラッシュを追加しましたrsync。ソースディレクトリをコピーするためにこれを行います。コンテンツ、ディレクトリ自体ではありません。

特別な機能を使用しないため、/bin/shスクリプトではなくスクリプトでスクリプトを作成しました。bashbash

テスト:

$ tree src
src
|-- data.dat
|-- subdir1
|   `-- myfile.txt
`-- subdir2
    `-- myfile.txt

2 directories, 3 files
$ linkcp src dst1

ファイルごとのリンク数は2つです。

$ ls -l dst1
total 8
-rw-r--r--  2 myself  wheel    0 Apr  6 07:47 data.dat
drwxr-xr-x  2 myself  wheel  512 Apr  6 07:47 subdir1
drwxr-xr-x  2 myself  wheel  512 Apr  6 07:47 subdir2
$ ls -l dst1/subdir*
dst1/subdir1:
total 0
-rw-r--r--  2 myself  wheel  0 Apr  6 07:47 myfile.txt

dst1/subdir2:
total 0
-rw-r--r--  2 myself  wheel  0 Apr  6 07:47 myfile.txt
$ linkcp src dst2

src構造の別のコピーを作成すると、リンク数が3に増えます。

$ ls -l dst2
total 8
-rw-r--r--  3 myself  wheel    0 Apr  6 07:47 data.dat
drwxr-xr-x  2 myself  wheel  512 Apr  6 07:47 subdir1
drwxr-xr-x  2 myself  wheel  512 Apr  6 07:47 subdir2
$ ls -l dst2/subdir*
dst2/subdir1:
total 0
-rw-r--r--  3 myself  wheel  0 Apr  6 07:47 myfile.txt

dst2/subdir2:
total 0
-rw-r--r--  3 myself  wheel  0 Apr  6 07:47 myfile.txt

関連情報