CDを関数にローカルに作成できますか?

CDを関数にローカルに作成できますか?

同様の機能を作成できますか?

function doStuffAt {
    cd $1
    # do stuff
}

しかし、関数を呼び出すと、実際に私のパスワードが変更されるわけではなく、関数が持続している間だけ変更されるという意味ですか?私はパスワードを保存して最後にリセットできることを知っていますが、それを心配することなくローカルでパスワードを設定する方法があることを望みました。

答え1

はい。グループコマンド( )の代わりにサブシェルで関数にコマンドを実行させます。{ }

doStuffAt() (
        cd -- "$1" || exit # the subshell if cd failed.
        # do stuff
)

角括弧(( ))は、親シェルの環境を継承する新しいサブシェルを開きます。サブシェルを実行するコマンドが完了すると、シャットダウンして親シェルに戻り、サブシェルcdにのみ影響するため、PWD は変更されません。

サブシェルはすべてのシェル変数もコピーするため、グローバル変数を介してサブシェル関数の情報をデフォルトのスクリプトに戻すことはできません。

サブシェルの詳細については、以下を確認してくださいman bash

(リスト)

listはサブシェル環境で実行されます(以下のコマンド実行環境を参照)。シェル環境に影響を与える変数割り当ておよび組み込みコマンドは、コマンドの完了後に無効になります。戻り状態はリストの終了状態です。

比較:

{リスト; }

listは現在のシェル環境でのみ実行されます。リストは改行またはセミコロンで終わる必要があります。これをグループコマンドと呼びます。戻り状態はリストの終了状態です。メタ文字(および)とは異なり、{と}は予約語であるため、予約語を認識できる場所に表示する必要があります。単語の分離を引き起こさないので、スペースやその他のシェルメタ文字でリストと区別する必要があります。

答え2

時々違うよね

この機能サブシェル。 (あなたも見ることができます角かっこは実際にコマンドをサブシェルに入れますか?)サブシェルで行われることはサブシェル内に残ります。変数、現在のディレクトリ、リダイレクト、トラップなどに対する関数の変更は、呼び出しコードには影響しません。子シェルは親シェルからこれらすべての属性を継承しますが、他の方向には渡されません。exitサブシェルでは、呼び出しプロセスではなくサブシェルのみを終了します。コードスニペットを括弧で囲んでサブシェルに入れることができます(括弧の前後の改行とスペースはオプションです)。

(
  set -e # to exit the subshell as soon as an error happens
  cd -- "$1"
  do stuff # in $1
)
do more stuff # in whatever directory was current before the '('

サブシェルで関数全体を実行するには、中かっこではなく括弧を使用して関数コードをラップできます。

doStuffAt () (
    set -e
    cd -- "$1"
    # do stuff
)

Kornスタイルの関数定義構文を使用するには、次の手順を実行する必要があります。

function doStuffAt { (
    set -e
    cd -- "$1"
    # do stuff
) }

サブシェルの欠点は、何もこれを抜け出すことができないことです。現在のディレクトリを変更した後にいくつかの変数を更新する必要がある場合は、サブシェルを使用してこれを行うことはできません。サブシェルから情報を取得する簡単な方法は2つだけです。他のコマンドと同様に、サブシェルにも終了状態がありますが、これは0から255の整数であるため、多くの情報を渡しません。あなたはそれを使用することができますコマンドの置き換え一部の出力の生成:コマンド置換は、標準出力(末尾の改行を除く)が文字列として収集されるサブシェルです。これにより文字列を出力できます。

data=$(
  set -e
  cd -- "$1"
  do stuff # in $1
)
# Now you're still in the original directory, and you have some data in $data

現在のディレクトリを変数に保存して後で復元できます。

set -e
old_cwd="$PWD"
cd -- "$1"
cd "$old_cwd"

ただし、この方法は信頼性が低下します。コードがcd2つのコマンドの間にある場合は、間違ったディレクトリにあります。この間に前のディレクトリが移動された場合、2番目のコマンドはcd正しい場所に戻りません。変更する権限がないディレクトリにある可能性があります(スクリプトが呼び出し元よりも権限が低いため)。この場合、2番目のコマンドはcd失敗します。したがって、制御された環境にない限り、この操作(cdスクリプトで生成された一時ディレクトリに入ってから出るなど)を実行しないでください。

一時的にディレクトリを変更し、何らかの方法で(変数の設定など)シェル環境に影響を与える必要がある場合は、スクリプトをシェル環境に影響を与える部分と現在のディレクトリを変更する部分に慎重に分離する必要があります。シェルは古いUnixシステムの制限を継承し、古いディレクトリに戻ることはできません。最新のUNIXシステムではそうしますが(現在のディレクトリのファイル記述子を「保存」してfchdir()例外ハンドラに返すことができます)、この機能のためのシェルインタフェースはありません。

答え3

いくつかのタスクを実行するために「一時的に」ディレクトリに入るとき(IOW、何らかの方法でディレクトリの変更範囲を制限したい場合)、そのディレクトリを活用することは合理的です。pushdとの使用は、popdビルドスクリプトなどの分野で一般的な技術です。

たくさんのプラグインを作っているとしましょう。

for plugindir in plugin1 plugin2 plugin2 plugin4; do
  pushd -- "$plugindir"
  make
  popd
done

答え4

サブシェルから呼び出します。

(doStuffAt some/path/)

関連情報