スクリプトの最後からすべての変数を削除するのは良い習慣ですか?

スクリプトの最後からすべての変数を削除するのは良い習慣ですか?

シェルスクリプトで使用された変数をスクリプトの最後から削除できますか?

rm -rf $abc
rm -rf $def

または

unset $abc
unset $def

など。

これは本当に良い習慣ですか?

答え1

これはとても悪い慣行。

rmファイルの削除。これは変数とは関係ありません。それにもかかわらず、スクリプトが終了し、オペレーティングシステムがシェルのメモリを回復すると、変数自体は解放されます。


単純なケースでは、変数のいずれかの値と同じ名前のファイルが次の構成によって削除されます。

abc=filename
rm -f $abc  # Deletes "filename" in the current directory

状況はさらに悪化します。ファイル名が含まれてabcいる場合defスペースで区切られた個々の単語(または他の文字)、これらのファイルを削除してワイルドカードが単語に表示されると、IFSワイルドカードも拡張されます。*

abc='hello world'
rm -f $abc  # Deletes file "hello" and "world" (leaves "hello world" alone)
abc='5 * 3'
rm -f $abc  # Deletes all files, because * is expanded (!)
def='-r /'
rm -f $def  # Really deletes *all* files this user can access

シェルパラメータは次に拡張されます。$var〜によって噴射ここで、変数の各文字はIFS変数を異なるパラメータに分割します。それからすべての言葉はファイル名拡張子の影響を受ける*?およびパターンを使用して[abc...]ファイル名を作成します。変数の内容によっては、状況が本当に悪くなることがあります。これをしないでください。


空にする必要はありません。未設定何らかの方法でシェルスクリプトの最後に変数を追加します。

答え2

実際にはシェル変数または一時ファイルを意味するのかどうか疑問に思います。

現在実行中のタスクが次の場合(一時ファイル):

tmp=$(mktemp)
something > "$tmp"
something else < "$tmp"
rm "$tmp"

もちろん、作業が終わったら一時ファイルを削除してください。スクリプトが途中でクラッシュしても、ファイルはそのまま残りますが、これはまれではありません。必要trap 'rm -f -- "$tmp"' EXITに応じて、シェルの終了時にファイルを削除できます。

ただし、個々のファイルを削除するときは、-f -r`を使用してくださいrm -f -- "$tmp", aswould help in avoiding error messages if the file was e.g. removed earlier for some reason. No reason to use

mktemp(また、基本的に「良い」ファイル名を生成しても、その変数を引用することを忘れないでください。)


しかし、これを行うと(変数):

read var
do something with "$var"
rm "$var"

だからあなたはしたくない:削除するファイルがなく、ユーザー入力のみがあります。シェルが終了すると、シェル変数は存在しなくなり、設定を解除する必要はありません。


ただし、スクリプトが別のシェルからインポートされた場合(または .bashrc同様のシェルにある場合)、スクリプトが終了してもシェルは終了しません。この場合、unset最後に使用した一時変数を維持し、残りのシェルの存続期間中にその設定を維持しないことが便利です。

# in .bashrc
__hour=$(date +%H)
if [ "$__hour" -lt 12 ] ; then echo "Good Morning!" ; 
elif [ "$__hour" -gt 18 ] ; then echo "Good Evening!" ;
fi
unset __hour

変数名はこのスクリプトの外で使用されている一部の変数とまだ競合する可能性があるため、名前を付けるときは注意が必要です。

答え3

今日、シェルスクリプトのエラー出力がブロックされました。その理由は、エクスポートされた環境変数が実際にシェルスクリプトにこっそり入り、不快な副作用を引き起こす可能性があるためです。具体的な方法は次のとおりです。

#!/bin/sh
#
line="$line $1"
echo $line

で呼び出すと、myscript.sh smeagolすでにエクスポートされたline変数が密かに入ってきます。unset lineスクリプト項目の汚染を防ぐ必要があります。

答え4

スクリプトの最後にすべての変数を設定解除するのは良い習慣ですか?1

シェルスクリプトはさまざまな方法で実行できます(以下の「1.シェルスクリプトを呼び出す方法」セクションを参照)、これはユースケースと意図によって異なります。これは、変数が元のシェル(シェルを呼び出したシェル)によって保持されているかどうかに影響します。スクリプト)かどうか。

たとえば、ting変数のいくつかのケースは次のとおりですunset

  • 悪いこのスクリプトの焦点は、環境変数を設定することです。サム

    そして、これもシェルスクリプトの呼び出し方法によって異なります(セクション1を参照)。

  • 悪いこのスクリプトはシェル変数を公開するように設計されています。何らかの目的で。

    例えば、スクリプトはより大きな「シェルスクリプトのコレクション」内の「モジュール」であり、他のシェルスクリプトはいわゆる「サブスクリプト」によって設定される変数に依存する。 (前の項目と同じ注意事項が適用されます。セクション1を参照してください。)

  • いいね、誰でも欲しいなら無知なユーザーを保護する(本人含む)と->前の事項が適用されない場合<-(そうでない場合が多い)。

    注:無知=知識が少ない

    たとえば、すべてのシェル変数が列挙される「設定解除セクション」(参照はい)時間と将来の痛みを軽減します。私は毎日シェルスクリプトを書いていませんし、執筆中に多くのコメントを残しますが、私の手の筋肉の記憶はスクリプトをどのように実行するのか気にしません。セッション(下記の「1.シェルスクリプトの呼び出し方法」のセクションをもう一度参照してください)。また、良い文書であっても、他の人がスクリプトを使用すると予想される場合は役に立ちません。これはしばしば無視されるからです(私の無知な自己を含む)。

  • (私は何を見逃していますか?)

1. シェルスクリプトの呼び出し方法

TL;DR
(サイトがマークダウンテーブルをサポートしていないため、ASCIIテーブル。この回答のより良い形式のバージョンを参照してください。この点.)

|    Shell script calling     |   Preserves     | Relevant  |
|          method             | variables and   | section   |
|                             |    exports      |           |
| --------------------------- | --------------- | --------- |
| `<interpreter> <file_name>` |        no       | 1.1       |
| `.`                         |        yes      | 1.2       | (workaround in 1.2.1) 
| executable script           |        no       | 1.3       |
| `source`                    |        yes      | 1.4       | (workaround in 1.2.1)

1.1<interpreter> <file_name>

たとえば、スクリプトを呼び出しscript.shてそのスクリプトを含むディレクトリから呼び出すとします。

  •     sh script.sh
  • bash script.sh
  •   zsh script.sh
  • fish script.sh

この方法はサブシェル高度なBashスクリプトガイド:第21章。サブシェル)、これは子プロセスの新しいシェルです。

シェルと環境変数廃棄されますスクリプトの実行が完了した後にスクリプトを呼び出したシェルは影響を受けません。

スクリプトのポイントが現在のシェルで使用する環境変数を設定することである場合は、次のようにします。

1.2個dot( .) POSIX 標準コマンド

関連トピック:stackoverflow処置: シェルスクリプトの完了後に環境変数を保持します。

.します」現在の環境でコマンドを実行する"(POSIX規格、ドットのマニュアルページ) 起動せずにサブシェル

シェルと環境変数有効なままスクリプトの実行が完了した後。

同じスクリプトを再実行すると、予期しない動作が発生する可能性があります。たとえば、次のスクリプトが与えられたら(と呼びますtest.sh

#!/usr/bin/env bash

# https://unix.stackexchange.com/questions/129391/passing-named-arguments-to-shell-scripts
while [ $# -gt 0 ]; do
  case "$1" in

    --option_a|-a)
      OPTION_A=$2
      ;;
    --option_b|-b)
      OPTION_B=$2
      ;;
    *)
      printf "***************************\n"
      printf "* Error: Invalid argument.*\n"
      printf "***************************\n"
      exit 1
  esac
  shift
  shift
done

# Setting default value if script is not called with `--option`
OPTION_A="${OPTION_A:-"default A"}"
OPTION_B="${OPTION_B:-"default B"}"

echo "OPTION_A: ${OPTION_A}"
echo "OPTION_B: ${OPTION_B}"

セクション1.1と1.3で説明されている方法で実行すると、すべてが正常です。

$ chmod +x test.sh
$ ./test.sh
OPTION_A: default A
OPTION_B: default B

$ bash test.sh -a 27
OPTION_A: 27
OPTION_B: default B

$ ./test.sh      
OPTION_A: default A
OPTION_B: default B

ただし、変数のデフォルト値を使用するには(コマンドラインオプションが次の場合)または.(以下のセクション1.4を参照)を使用します。sourceいいえ場合:

# source test.sh === . ./test.sh

$ source test.sh
OPTION_A: default A
OPTION_B: default B

$ . ./test.sh -a 27 
OPTION_A: 27
OPTION_B: default B

$ source test.sh      
OPTION_A: 27
OPTION_B: default B

1.2.1現在のシェルを台無しにせずに.(and)を使用する方法は?source

括弧((および))を使用すると、その間のコマンドがサブシェル(セクション1.1と1.3と同じ方法)。

たとえば、( source test.sh )

関連文書とスレッド:

1.3 スクリプトファイルの実行可能ビットの設定

上記の「1.1」の説明を参照してください<interpreter> <file_name>

関連トピック:unix&linux:Bashにsource実行ビットが必要ない理由は何ですか?

たとえば、スクリプトを呼び出しscript.shてそのスクリプトを含むディレクトリから呼び出すとします。

$ chmod +x script.sh

$ ./script.sh

1.4sourceコマンド

ポイントの同義語(.'1.2参照)ドット(.)POSIX標準コマンド」セクションの上)。

私が知っている限り、この同義語はbash、fish、zshにありますが、他のシェルにも存在するかもしれませんが、source移植性のためによく使用されます。.

関連トピック:unix&linux:ソースのエイリアスとしてドット(.)を使用するのはなぜですか?なぜ他のコマンドにショートカットがないのですか?


脚注

[1]:質問をもう一度言うと、ここの答えは変数に焦点を当て、rm変数を設定解除しないからです。要約する:

  • rmファイルの削除

  • unset

    これは$次の目的に使用されます。パラメータ拡張GNU Bashドキュメント、3.5.3シェルパラメータの拡張)この場合2、以前は必要ありませんでした。それ以外の場合は、参照しているコンテンツをvariable_name設定解除しようとします。variable_name

    $ abc=27
    $ def=abc
    
    $ echo "abc=${abc}; def=${def}"
    abc=27; def=abc
    
    #       v
    $ unset $def
    #       ^
    $ echo "abc=${abc}; def=${def}"
    abc=; def=abc
    
    #       V
    $ unset  def
    #       ^
    $ echo "abc=${abc}; def=${def}"
    abc=; def=
    

    しかし、少し複雑かもしれません。unix&linuxunsetそれは何をしますか?

[2]: また参照stackoverflow:特殊ドル記号シェル変数は何ですか?

[3]: このトピックの良いトピック:

関連情報