シンプルなbashスクリプトが動作しない

シンプルなbashスクリプトが動作しない

このスクリプトは、コマンドラインで引数として名前が指定されているすべてのファイルをユーザーのホーム ディレクトリにコピーします。ファイルが指定されていない場合、スクリプトは read を使用してファイル名を要求し、応答で指定されたすべてのファイル名をユーザーのホーム ディレクトリにコピーします。

if [ -z $1 ]
then
    echo provide filenames
    read $FILENAMES
else
    FILENAMES="$@"
fi

echo the following filenames have been provided: $FILENAMES
for i in $FILENAMES
do
    cp $i $HOME
done

引数を文字列として指定すると、動作します。ただし、「read $FILENAMES」として指定すると、動作しません。

メンターはレッスンで同じ解決策を示しましたが、それがどのように機能するかは示しませんでした。 ここに画像の説明を入力してください

更新ファイル名を引数として入力すると、空の文字列が返され、$HOMEの場所にファイルがコピーされませんでした

[dmytro@oc1726036122 ~]$ cd Desktop/
[dmytro@oc1726036122 Desktop]$ . totmp 
provide filenames
one two
the following filenames have been provided:
the following filenames have been provided:
[dmytro@oc1726036122 Desktop]$

答え1

read変数を読み取るのではなく、宣言します。簡単に言うと、$から を削除すればread準備完了です。

if [ -z $1 ]
then
    echo provide filenames
    read FILENAMES
else
    FILENAMES="$@"
fi

echo the following filenames have been provided: $FILENAMES
for i in $FILENAMES
do
    cp $i $HOME
done

編集:スクリプトを実行するためにsource( ) コマンドを使用していることがわかりました。.

[dmytro@oc1726036122 Desktop]$ . totmp

この特定のスクリプトでは問題ないかもしれませんが、複雑なスクリプトでは絶対にそうしないでください。そうしないと、そのスクリプトの変数や関数をシェルに取り込むことになります。bash totmp

答え2

あなたを妨げている問題は、readコマンドが正しくないことです。コマンドに渡される引数は変数名である必要があるため、 なしで渡す必要があります$( は$変数の内容を展開しますが、その時点では空なので、結果はread変数名が渡されない になります)。

read FILENAMES

最初のコマンドライン引数が存在しないかどうかのチェックには、別の問題があります。引数が存在しない場合は、$1何も展開されません (空の文字列ではありません)。この場合、引数が有効ではないはずな[ので、コマンドで問題が発生する可能性があります。つまり、その変数を引用符で囲む必要があります。[ -z ][ -z "" ]

if [ -z "$1" ]

bash を使用している場合は、 を使用することもできます[[ ... ]]。これは内部コマンドなので、通常はこちらの方が適しています (その場合、このコマンドは引用符なしでも機能しますが、引用符を付けたままでも問題はありませんし、見栄えも良くなります)。

(追記: このスクリプトには他にも多くの問題があり、ベストプラクティスからは程遠いので、誰かがこれを教えるのを見ると本当に驚きます。残念ながら、bash を教えるハードルは非常に低く、実際によく理解するまでマニュアルは非常に複雑なので、適切に学習する方法について、私にもより良いアドバイスがあるかどうかわかりません。)☹️

答え3

コマンドreadは変数を取りますが、すでに変数の値を参照しています。

 #correct syntax
 read variable
 #wrong syntax
 read $variable

$variableは の値でありvariable、スクリプトの先頭ではこれは未設定/空です。

関連情報