スペースと特殊文字を含むcpは端末ではうまく機能しますが、スクリプトでは機能しません。

スペースと特殊文字を含むcpは端末ではうまく機能しますが、スクリプトでは機能しません。

ファイルを見つけて特定のフォルダにコピーするスクリプトを作成しようとしています。ファイル名にはスペースやその他の特殊文字が含まれています。

a=$(ls ~/Downloads/ | grep $1)
a="'$a'"
a="~/Downloads/"$a
echo $a
cp $a ~/Documents/books/.

ファイル名を引用すると、端末で正常に動作します。ただし、スクリプトでは、これらの単語は別々のパラメータとして扱われます。上記のスクリプトで$aがエコーされると、次のようになります。

~/Downloads/'Ian Goodfellow, Yoshua Bengio, Aaron Courville - Deep Learning [pre-pub version] (2016, MIT Press).pdf'

参照されるファイル名を表示できます。上記のパラメータが端末のcpに渡された場合は正しく機能しますが、スクリプトでは機能しません。助けてください。

答え1

~/Downloadsからとして特定のファイルをコピーしたいようです~/Documents/books

最初に注目すべき点は、~変数として機能しないことです。特に、はいいいえ参照時にホームディレクトリへのパスに展開します。したがって、スクリプトでは$HOME

2つ目は、変数の値に一重引用符を追加するようです$a。これは不要で、「ファイルまたはディレクトリがありません」というエラーのみが発生します(ファイル名に一重引用符がないため)。

ls3番目は、スクリプトで使用しないようにする必要があることです。たとえば、この場合、$1ファイル名のみを~/Downloads検索する必要はありません。また、次のようなgrep $1さまざまな理由で使用に問題があります。

  • grep主にテキストに使用されます文書。理論的には、ファイル名に改行文字を含めることができるため、名前が既知の場合、または「良好」の場合にのみファイル名を「grepping」できます。
  • $1引用符で囲まれていないため、grepスペースやその他の特殊文字が含まれていると混乱を招く可能性があります。たとえば、$1現在のディレクトリのすべてのファイル名に展開されます。*
  • 文字列が$1ダッシュで始まると、オプションとして扱われますgrep

したがって、スクリプトは次のように書くことができます。

#!/bin/sh

name="$HOME/Downloads/$1"

printf 'The filename is "%s"\n' "$name"

cp "$name" "$HOME/Documents/books"

ここでコマンドは、printf選択したファイルの名前を出力することです。はい出力名前の周りに二重引用符がありますが、名前には二重引用符があります。いいえ中に二重引用符があります。代わりに、$name最後の行に通話の内容を必ず引用しました。cp実際に引用しなければなりません。みんなそれ以外の場合、拡張によってシェルが変数値を分割することがわかります。

このスクリプトは次のように使用できます。

./script.sh 'Ian Goodfellow, Yoshua Bengio, Aaron Courville - Deep Learning [pre-pub version] (2016, MIT Press).pdf'

ファイル名にはシェルに特殊なスペースと文字が含まれているため、引用符で囲む必要があります。

スクリプトがコマンドラインで指定された単語を含むファイルを見つけるようにするには、次のように言うことができます。

./script.sh Goodfellow

次に、指定された文字列をワイルドカードパターンとして使用します。

#!/bin/sh

for name in "$HOME/Downloads"/*"$1"*.pdf; do
    printf 'Will copy the file "%s"\n' "$name"
    cp "$name" "$HOME/Documents/books"
done

スクリプトは最初のパラメータを使用して、ファイル名に指定された文字列を含むすべてのファイルを繰り返します.pdf~/Downloadsこれらの各ファイルはにコピーされます~/Documents/books

cp -vファイルが詳細にコピーされるUnixを使用している場合、スクリプトの範囲がさらに狭くなる可能性があります。

#!/bin/sh

cp -v "$HOME/Downloads"/*"$1"*.pdf "$HOME/Documents/books"

これにより、指定されたパターンに一致するファイル名を繰り返さなくなり、ユーザーが直接出力形式を指定するのを防ぎます(「Will copy...」)。代わりに、複数のファイル名が与えられた場合cp(ワイルドカードパターンは主に複数のファイル名に拡張される可能性が高い)、単一のコマンドを使用していくつかのターゲットディレクトリにコピーできることに依存します。


また見なさい:

関連情報