私は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/test
2つのファイルです。test1
test2
これを行うには、何を変更する必要があるのかを理解するのに役立つ人がいますか?ありがとうございます。
答え1
このような短いユーティリティスクリプトにはお勧めしますいいえインタラクティブにしてください。ユーザーは、説明した方法でコピーしたいディレクトリを正確に知っている可能性があり、ユーザーがコマンドラインでタブの完成および/またはファイル名のグロービングを使用できるようにすると、次のように入力するのと同じ結果が得られる可能性が高くなります。メモリから取得したパラメータと比較すると、パラメータは正確です。
また、私はls
他のものを使用しませんファイルリストを見る。ls
ファイル名を読み取るためにスクリプトで使用しないでください。ファイル名グロービングパターンを使用するのが最善です。これについては他のQ&Aで詳しく説明します。なぜ`ls`を解析しないのですか*(そしてどうすればいいですか?)
スクリプトを終了するには、最後まで実行するか、を使用しますexit
。kill
また、通常、単語の区切りや不要なファイル名のグロービングを防ぐために、すべての変数拡張子を二重引用符で囲みます。いつ二重引用符が必要ですか?)。
中かっこ拡張内でシェル変数を使用しようとすると、特定のエラーが発生します。これは不可能です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-dest
rsync
readlink
この方法では、rsync
ソースディレクトリがターゲットディレクトリパスで繰り返し生成され(ソースとターゲットが同じファイルシステムにある場合)、ディレクトリ以外のファイルがハードリンクされます。ソースパスとターゲットパスが異なるファイルシステムにある場合、ソースディレクトリパスは再帰的です。コピー代わりにハードリンクは作成されません。
呼び出しのソースパラメータの末尾にスラッシュを追加しましたrsync
。ソースディレクトリをコピーするためにこれを行います。コンテンツ、ディレクトリ自体ではありません。
特別な機能を使用しないため、/bin/sh
スクリプトではなくスクリプトでスクリプトを作成しました。bash
bash
テスト:
$ 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