シェルスクリプトを作成しています。 (シェルを使用するバージョンとオペレーティングシステムは次のとおりです。)このスクリプトは、ローカルのgitリポジトリ/ディレクトリで複数のタグを含むコマンドを実行します。スクリプトは、リポジトリタグ名に基づいて選択されたディレクトリのgrepファイルからいくつかの文字列を出力します。
zsh --version
zsh 5.9 (x86_64-apple-darwin22.0)
OS: System Version: macOS 13.6.3
+
using oh-my-zsh, https://ohmyz.sh/
このスクリプトはcd
ディレクトリ(コマンド)をgitローカルリポジトリに変更します。次に、配列のラベルを取得するプロセスを経ますMY_ARRAY=($(git tag))
。次に、各ストレージタグに対してgit checkout $my_tag --quiet
そのタグに対してアクションを実行します。その後、cd
リポジトリのディレクトリ(directoryA)にあります。次に、pwd
作業ディレクトリを確認するためにaを実行します/git-repository/directoryA
。pwd
この時点の出力は予想通りです(/git-repository/directoryA
)。これがあると、/git-repository/directoryA
スクリプトはLIST_OF_SUBDIRECTORIES=($(ls -d */))
のサブディレクトリ配列を取得します。directoryA
出力は次のとおりですLIST_OF_SUBDIRECTORIES is cw-events/ cw-metric-alarm/ eventbridge-scheduler/ msk/ secrets-manager/ ses/ sns-topic/ sqs/ ssm-params/ xlate/
。各サブディレクトリ(for
ループを使用)に対して、スクリプトは次のcd
ようにLIST_OF_SUBDIRECTORIES配列のサブディレクトリを指す必要があります。
if echo "$my_tag" | grep -q -E "$MY_SUBDIRECTORY"; then
echo "MY_SUBDIRECTORY is $MY_SUBDIRECTORY"
set -x
cd $MY_SUBDIRECTORY 2>&1 | tee -a log_file.txt
set +x
echo "PWD Working Directory is $(pwd)"
if条件の出力がecho "MY_SUBDIRECTORY is $MY_SUBDIRECTORY"
trueなのでスクリプトを入力MY_SUBDIRECTORY is cw-events/
できるようにしたいのですが上記の内容が出力されています。スクリプトはで始まります。試行中にエラーが発生します。他の問題を発見しましたcd
cw-events/
echo "PWD Working Directory is $(pwd)"
/git-repository/directoryA
#!/bin/zsh
#!/bin/bash
https://blog.kubesimplify.com/how-to-change-directory-in-shell-scriptsまたは現在のディレクトリを変更するスクリプト(cd、pwd)しかし実際には、親シェルではなくサブシェルのディレクトリを変更したいと思います。の
中にスクリプト/git-repository/directoryA
がにないのはなぜですか?出力例:私ができる簡単な例はスクリプト実行の出力です。cd
/git-repository/directoryA/subdirectory-of-A
FIRST-SUB-Directory is /git-repository/directoryA
LIST_OF_SUBDIRECTORIES is cw-events/ secrets-manager/ sqs/ ssm-params/
MY_SUBDIRECTORY is cw-events/
+/path/to/script/script.sh:44> cd cw-events/
+/path/to/script/script.sh:44> tee -a log_file.txt
+/path/to/script/script.sh:45> set +x
PWD Working Directory is /git-repository/directoryA
ありがとうございます。
答え1
この行は明らかに間違っています。
cd $MY_SUBDIRECTORY 2>&1 | tee -a log_file.txt
パイプの左側はサブシェルで実行されます。これは、内部変更(変数、現在のディレクトリなど)がプライマリシェルに影響を与えないことを意味します。バラよりCDをレコーダーにリダイレクトできないロギングの追加の説明とアドバイス。cd -
// cd -2
...cd +2
ディレクトリスタックを検索するときを除いてcd
失敗しない限り、出力はエクスポートされないため、出力を記録することはとにかく意味がありません。
cd $MY_SUBDIRECTORY
行を(またはより良い場合)に変更すると、cd -- $MY_SUBDIRECTORY
少なくとも公開したスクリプト部分に対してディレクトリ変更が機能します。スクリプトの後半でまだ元のディレクトリにある場合は、サブシェルを作成するために別の作業を行っている可能性があります(まだ公開していないコードの一部)。
それ以外には目立って間違ったことはありませんが、いくつかは必要以上に複雑です。間違いのリスクを減らすために、より簡単な方法でタスクを実行することをお勧めします。
あなたは使う
echo
そしてset -x
そして| tee …
文書化する。一つで十分です。set -x
ほとんどの場合は大丈夫です。パイピングはtee
スクリプトの動作(サブシェルの作成、ファイル記述子の変更、エラーの非表示)に影響を与えるため、難しいです。echo "$my_tag" | grep -q -E "$MY_SUBDIRECTORY"
値に拡張正規表現演算子(commonタグやgitタグなど)が含まれていないとし、値に部分文字列値がmy_tag
含まれていることを確認してください。簡単に確認する方法があります。MY_SUBDIRECTORY
MY_SUBDIRECTORY
.
+
if [[ $my_tag = *"$MY_SUBDIRECTORY"* ]]; then …
LIST_OF_SUBDIRECTORIES=($(ls -d */))
LIST_OF_SUBDIRECTORIES=( *(-/) )
zsh を使用して作成できます。/
グローバル予選、ファイルタイプ、およびその他の特性でグローブをフィルタリングできます。ここで、-
so型チェックと組み合わせた操作は、シンボリックリンクの確認後に行われます*/
。各要素の末尾にスラッシュは追加されません。…=( *(-/M) )
スラッシュが本当に必要な場合や使用可能なディレクトリのみをリストする特別な場合には機能します…=( */ )
が、実際にはスラッシュは必要ないかもしれません。N
サブディレクトリがない場合に致命的なエラーの代わりに空のリストを取得するには、glob修飾子を追加してください。LIST_OF_SUBDIRECTORIES=( *(N-/) )
echo "$my_tag"
厳密に言えば、as出力のすべての行はgrep
一度に1行ずつ一致し、改行文字にも拡張echo
されます\n
(幸いにも、gitタグにバックスラッシュが含まれていないことを保証する必要があります)。
答え2
cmd1 | cmd2
、同時にcmd1
実行されるため、別々cmd2
のプロセスで実行する必要があります。
多くのシェルでは、組み込まれていても(たとえばcd
)サブプロセスで実行されます。 kshと同様に、zshでもcmd2
組み込まれている場合は、現在のシェルプロセスで実行されますが、cmd1
常に子プロセスで実行されます。
そのため、cd ... | tee ...
サブcd
プロセスを実行し、その短期サブプロセスの作業ディレクトリのみを変更してください。
ただし、zshにはtee
機能が組み込まれているため、これを行う必要はありません。あなたはできます:
cd -- $MY_SUBDIRECTORY >&1 >> file.log 2>&2 2>> file.log || exit
fdが書き込み用に複数回リダイレクトされると、zshはパイプを介してバックグラウンドtee
で同様の機能を実行するプロセスにリダイレクトします。
ここでは fd 1 を>&1
( ) にリダイレクトしています。これは通常は機能しませんが、ここでは標準出力をそこに置いて追加モードにリダイレクトするという意味ですfile.log
。 fd 2(stderr)でも同じことを行います。これはcd 2>&1 | tee
、whereバンドルのtee
標準出力に対する一般的なメッセージとエラーメッセージに対するもう1つの改善ですcd
。
もう1つの改善は、終了状態が保存されることですcd
。失敗した場合は、スクリプトの残りの部分を続行しないように|| exit
するために1つを追加しました。cd
などのものは、ディレクトリスタックをナビゲートしたときにstdoutからのみ出力されますcd
。ここではそうではありませんので、ただ使用できます。cd -
cd -2
cd +2
cd ... 2>&2 2>> file.log
また、この方法もユーザーの方法も出力をリダイレクトしませtee
んxtrace
。 stderrに移動しますが、それ自体は出力しません。 xtrace出力をキャプチャするには、その中で実行されているコマンドグループcd
をリダイレクトする必要があります。cd
それは次のとおりです。
set -x # or set -o xtrace
{
cd -- $MY_SUBDIRECTORY
} 2>&1 2>> file.log
set +x
関数または匿名関数でローカルでオプションを有効にすることもでき、実行する代わりにトレースが表示されset -x
ますset +x
。set +x
xtrace
() {
set -o localoptions -o xtrace
cd -- $MY_SUBDIRECTORY
} 2>&2 2>> file.log
または、ヘルパー機能を使用してください。
trace() {
set -o localoptions -o xtrace
"$@"
} >&1 >> file.log 2>&2 2>> file.log
trace cd -- $MY_SUBDIRECTORY || exit
または、次のようにfunctions -t
kshで関数トレースを有効にします。
trace() {
"$@"
} >&1 >> file.log 2>&2 2>> file.log
functions -t trace
trace cd -- $MY_SUBDIRECTORY || exit
、、...echo
などのエスケープシーケンスをデフォルトで拡張し、オプションを許可します。改行文字の後にそのまま出力するには、次の手順を実行する必要があります。\n
\uXXXX
\0123
echo -E - $something
printf
ただし、通常は(shと互換性があります)または(kshと互換性があり、より一般的な)を使用することをお勧めします。print
printf '%s\n' "$something"
print -r -- "$something"
また、これはpwd
stuffを印刷する組み込みコマンド$PWD
なので、$(pwd)
少し意味がありません。
print -r "PWD Working Directory is $PWD"
もっと理解できるでしょう。