github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/os/exec/exec.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // execパッケージは外部コマンドを実行します。これはos.StartProcessをラップして、 6 // stdinとstdoutのリマップ、パイプを使用したI/Oの接続、その他の調整を 7 // 簡単に行うことができます。 8 // 9 // Cや他の言語からの"system"ライブラリ呼び出しとは異なり、 10 // os/execパッケージは意図的にシステムシェルを呼び出さず、 11 // グロブパターンを展開したり、シェルが通常行う他の展開、 12 // パイプライン、リダイレクションを処理しません。このパッケージは 13 // Cの"exec"関数群のように振る舞います。グロブパターンを展開するには、 14 // シェルを直接呼び出し、危険な入力をエスケープするか、 15 // [path/filepath] パッケージのGlob関数を使用します。 16 // 環境変数を展開するには、osパッケージのExpandEnvを使用します。 17 // 18 // このパッケージの例はUnixシステムを前提としています。 19 // これらはWindowsでは実行できないかもしれませんし、golang.org や godoc.org が使用する 20 // Go Playgroundでは実行できません。 21 // 22 // # Executables in the current directory 23 // 24 // 関数 [Command] と [LookPath] は、ホストオペレーティングシステムの規則に従って、 25 // 現在のパスにリストされたディレクトリでプログラムを探します。 26 // オペレーティングシステムは何十年もの間、この検索に現在の 27 // ディレクトリを含めてきました。これは時々暗黙的に、時々 28 // デフォルトで明示的にそのように設定されています。 29 // 現代の慣行では、現在のディレクトリを含めることは通常予期しないもので、 30 // しばしばセキュリティ問題につながります。 31 // 32 // これらのセキュリティ問題を避けるために、Go 1.19から、このパッケージはプログラムを 33 // 現在のディレクトリに対する暗黙的または明示的なパスエントリを使用して解決しません。 34 // つまり、[LookPath]("go")を実行すると、パスがどのように設定されていても、 35 // Unixでは./go、Windowsでは.\go.exeを正常に返すことはありません。 36 // 代わりに、通常のパスアルゴリズムがその答えをもたらす場合、 37 // これらの関数はエラーerrを返し、[errors.Is](err, [ErrDot])を満たします。 38 // 39 // 例えば、以下の2つのプログラムスニペットを考えてみてください: 40 // 41 // path, err := exec.LookPath("prog") 42 // if err != nil { 43 // log.Fatal(err) 44 // } 45 // use(path) 46 // 47 // そして 48 // 49 // cmd := exec.Command("prog") 50 // if err := cmd.Run(); err != nil { 51 // log.Fatal(err) 52 // } 53 // 54 // これらは、現在のパスの設定に関係なく、./progや.\prog.exeを見つけて実行することはありません。 55 // 56 // 常に現在のディレクトリからプログラムを実行したいコードは、"prog"の代わりに"./prog"と指定することで書き換えることができます。 57 // 58 // 相対パスエントリからの結果を含めることに固執するコードは、代わりに errors.Is チェックを使用してエラーをオーバーライドできます: 59 // 60 // path, err := exec.LookPath("prog") 61 // if errors.Is(err, exec.ErrDot) { 62 // err = nil 63 // } 64 // if err != nil { 65 // log.Fatal(err) 66 // } 67 // use(path) 68 // 69 // そして 70 // 71 // cmd := exec.Command("prog") 72 // if errors.Is(cmd.Err, exec.ErrDot) { 73 // cmd.Err = nil 74 // } 75 // if err := cmd.Run(); err != nil { 76 // log.Fatal(err) 77 // } 78 // 79 // 環境変数GODEBUG=execerrdot=0を設定すると、 80 // ErrDotの生成が完全に無効になり、よりターゲット指向の修正を適用できないプログラムに対して、 81 // 一時的にGo 1.19以前の動作が復元されます。 82 // Goの将来のバージョンでは、この変数のサポートが削除される可能性があります。 83 // 84 // そのようなオーバーライドを追加する前に、 85 // それを行うことのセキュリティ上の意味を理解しておいてください。 86 // 詳細は https://go.dev/blog/path-security を参照してください。 87 package exec 88 89 import ( 90 "github.com/shogo82148/std/context" 91 "github.com/shogo82148/std/errors" 92 "github.com/shogo82148/std/io" 93 "github.com/shogo82148/std/os" 94 "github.com/shogo82148/std/syscall" 95 "github.com/shogo82148/std/time" 96 ) 97 98 // Errorは、[LookPath] がファイルを実行可能なものとして分類できなかったときに返されます。 99 type Error struct { 100 // Nameは、エラーが発生したファイル名です。 101 Name string 102 // Errは、基になるエラーです。 103 Err error 104 } 105 106 func (e *Error) Error() string 107 108 func (e *Error) Unwrap() error 109 110 // ErrWaitDelayは、プロセスが成功したステータスコードで終了するが、 111 // コマンドのWaitDelayが期限切れになる前にその出力パイプが閉じられない場合、 112 // [Cmd.Wait] によって返されます。 113 var ErrWaitDelay = errors.New("exec: WaitDelay expired before I/O complete") 114 115 // Cmdは、準備中または実行中の外部コマンドを表します。 116 // 117 // Cmdは、[Cmd.Run]、[Cmd.Output]、または [Cmd.CombinedOutput] メソッドを呼び出した後では再利用できません。 118 type Cmd struct { 119 // Pathは、実行するコマンドのパスです。 120 // 121 // これは唯一、ゼロ以外の値に設定しなければならないフィールドです。 122 // Pathが相対パスの場合、Dirに対して相対的に評価されます。 123 Path string 124 125 // Argsはコマンドライン引数を保持します。コマンド自体はArgs[0]として含まれます。 126 // Argsフィールドが空またはnilの場合、Runは{Path}を使用します。 127 // 128 // 典型的な使用では、PathとArgsの両方はCommandを呼び出すことで設定されます。 129 Args []string 130 131 // Envはプロセスの環境を指定します。 132 // 各エントリは "key=value" の形式です。 133 // Envがnilの場合、新しいプロセスは現在のプロセスの 134 // 環境を使用します。 135 // Envに環境キーの重複が含まれている場合、各重複キーに対してスライス内の 136 // 最後の値のみが使用されます。 137 // Windowsでは特別なケースとして、SYSTEMROOTは常に追加されます。 138 // 明示的に空文字列に設定されていない場合は欠落しています。 139 Env []string 140 141 // Dirはコマンドの作業ディレクトリを指定します。 142 // Dirが空文字列の場合、Runは呼び出し元プロセスの現在のディレクトリでコマンドを実行します。 143 Dir string 144 145 // Stdinはプロセスの標準入力を指定します。 146 // 147 // Stdinがnilの場合、プロセスはnullデバイス(os.DevNull)から読み取ります。 148 // 149 // Stdinが*os.Fileの場合、プロセスの標準入力はそのファイルに直接接続されます。 150 // 151 // それ以外の場合、コマンドの実行中に別のgoroutineがStdinから読み取り、 152 // そのデータをパイプ経由でコマンドに送信します。この場合、Waitはgoroutineが 153 // コピーを停止するまで完了しません。これは、Stdinの終わりに達したため(EOFまたは読み取りエラー)、 154 // パイプへの書き込みがエラーを返したため、または非ゼロのWaitDelayが設定されて期限切れになったためです。 155 Stdin io.Reader 156 157 // StdoutとStderrは、プロセスの標準出力とエラーを指定します。 158 // 159 // どちらかがnilの場合、Runは対応するファイルディスクリプタを 160 // nullデバイス(os.DevNull)に接続します。 161 // 162 // どちらかが*os.Fileの場合、プロセスからの対応する出力は 163 // そのファイルに直接接続されます。 164 // 165 // それ以外の場合、コマンドの実行中に別のgoroutineがプロセスからパイプ経由で読み取り、 166 // そのデータを対応するWriterに送信します。この場合、Waitはgoroutineが 167 // EOFに達するか、エラーに遭遇するか、非ゼロのWaitDelayが期限切れになるまで完了しません。 168 // 169 // StdoutとStderrが同じWriterで、==で比較できる型を持っている場合、 170 // 同時に最大1つのgoroutineだけがWriteを呼び出します。 171 Stdout io.Writer 172 Stderr io.Writer 173 174 // ExtraFilesは、新しいプロセスに継承される追加のオープンファイルを指定します。 175 // 標準入力、標準出力、または標準エラーは含まれません。非nilの場合、エントリiは 176 // ファイルディスクリプタ3+iになります。 177 // 178 // ExtraFilesはWindowsではサポートされていません。 179 ExtraFiles []*os.File 180 181 // SysProcAttrは、オプションのオペレーティングシステム固有の属性を保持します。 182 // Runは、os.ProcAttrのSysフィールドとしてos.StartProcessに渡します。 183 SysProcAttr *syscall.SysProcAttr 184 185 // Processは、開始された後の基本的なプロセスです。 186 Process *os.Process 187 188 // ProcessStateは、終了したプロセスに関する情報を含みます。 189 // プロセスが正常に開始された場合、コマンドが完了するとWaitまたはRunが 190 // そのProcessStateを設定します。 191 ProcessState *os.ProcessState 192 193 // ctx is the context passed to CommandContext, if any. 194 ctx context.Context 195 196 Err error 197 198 // Cancelがnilでない場合、コマンドはCommandContextで作成されていなければならず、 199 // コマンドのContextが完了したときにCancelが呼び出されます。デフォルトでは、 200 // CommandContextはCancelをコマンドのProcessのKillメソッドを呼び出すように設定します。 201 // 202 // 通常、カスタムCancelはコマンドのProcessにシグナルを送信しますが、 203 // 代わりにキャンセルを開始するための他のアクションを取ることもあります。 204 // 例えば、stdinやstdoutのパイプを閉じる、またはネットワークソケットにシャットダウンリクエストを送信するなどです。 205 // 206 // Cancelが呼び出された後にコマンドが成功ステータスで終了し、 207 // そしてCancelがos.ErrProcessDoneと等価のエラーを返さない場合、 208 // Waitや類似のメソッドは非nilのエラーを返します:Cancelによって返されたエラーをラップするエラー、 209 // またはContextからのエラーです。 210 // (コマンドが非成功ステータスで終了する場合、またはCancelがos.ErrProcessDoneをラップするエラーを返す場合、 211 // Waitや類似のメソッドは引き続きコマンドの通常の終了ステータスを返します。) 212 // 213 // Cancelがnilに設定されている場合、コマンドのContextが完了したときにはすぐには何も起こりませんが、 214 // 非ゼロのWaitDelayは依然として効果を発揮します。これは、例えば、シャットダウンシグナルをサポートしていないが、 215 // 常にすぐに終了することが期待されるコマンドのデッドロックを回避するために役立つかもしれません。 216 // 217 // Startが非nilのエラーを返す場合、Cancelは呼び出されません。 218 Cancel func() error 219 220 // WaitDelayが非ゼロの場合、Waitで予期しない遅延の2つの源に対する待機時間を制限します: 221 // 関連するContextがキャンセルされた後も終了しない子プロセス、およびI/Oパイプを閉じずに終了する子プロセス。 222 // 223 // WaitDelayタイマーは、関連付けられたContextが完了したとき、または 224 // Waitの呼び出しで子プロセスが終了したことが確認されたときのいずれか早い方から開始します。 225 // 遅延が経過すると、コマンドは子プロセスと/またはそのI/Oパイプをシャットダウンします。 226 // 227 // 子プロセスが終了に失敗した場合 — たとえば、Cancel関数からのシャットダウンシグナルを無視したり、 228 // 受信に失敗したりした場合、またはCancel関数が設定されていなかった場合 — それはos.Process.Killを使用して終了されます。 229 // 230 // その後、子プロセスと通信するI/Oパイプがまだ開いている場合、 231 // それらのパイプは、現在ReadまたはWrite呼び出しでブロックされているgoroutineを解除するために閉じられます。 232 // 233 // WaitDelayによりパイプが閉じられ、Cancelの呼び出しが行われておらず、 234 // コマンドがそれ以外の点で成功ステータスで終了した場合、Waitや類似のメソッドは 235 // nilの代わりにErrWaitDelayを返します。 236 // 237 // WaitDelayがゼロ(デフォルト)の場合、I/OパイプはEOFまで読み取られます。 238 // これは、コマンドの孤立したサブプロセスもパイプのディスクリプタを閉じるまで発生しないかもしれません。 239 WaitDelay time.Duration 240 241 // childIOFiles holds closers for any of the child process's 242 // stdin, stdout, and/or stderr files that were opened by the Cmd itself 243 // (not supplied by the caller). These should be closed as soon as they 244 // are inherited by the child process. 245 childIOFiles []io.Closer 246 247 // parentIOPipes holds closers for the parent's end of any pipes 248 // connected to the child's stdin, stdout, and/or stderr streams 249 // that were opened by the Cmd itself (not supplied by the caller). 250 // These should be closed after Wait sees the command and copying 251 // goroutines exit, or after WaitDelay has expired. 252 parentIOPipes []io.Closer 253 254 // goroutine holds a set of closures to execute to copy data 255 // to and/or from the command's I/O pipes. 256 goroutine []func() error 257 258 // If goroutineErr is non-nil, it receives the first error from a copying 259 // goroutine once all such goroutines have completed. 260 // goroutineErr is set to nil once its error has been received. 261 goroutineErr <-chan error 262 263 // If ctxResult is non-nil, it receives the result of watchCtx exactly once. 264 ctxResult <-chan ctxResult 265 266 // The stack saved when the Command was created, if GODEBUG contains 267 // execwait=2. Used for debugging leaks. 268 createdByStack []byte 269 270 // For a security release long ago, we created x/sys/execabs, 271 // which manipulated the unexported lookPathErr error field 272 // in this struct. For Go 1.19 we exported the field as Err error, 273 // above, but we have to keep lookPathErr around for use by 274 // old programs building against new toolchains. 275 // The String and Start methods look for an error in lookPathErr 276 // in preference to Err, to preserve the errors that execabs sets. 277 // 278 // In general we don't guarantee misuse of reflect like this, 279 // but the misuse of reflect was by us, the best of various bad 280 // options to fix the security problem, and people depend on 281 // those old copies of execabs continuing to work. 282 // The result is that we have to leave this variable around for the 283 // rest of time, a compatibility scar. 284 // 285 // See https://go.dev/blog/path-security 286 // and https://go.dev/issue/43724 for more context. 287 lookPathErr error 288 } 289 290 // Commandは、指定されたプログラムを 291 // 与えられた引数で実行するための [Cmd] 構造体を返します。 292 // 293 // それは返される構造体の中でPathとArgsだけを設定します。 294 // 295 // nameにパスセパレータが含まれていない場合、Commandは [LookPath] を使用して 296 // 可能な場合にはnameを完全なパスに解決します。それ以外の場合、nameを 297 // 直接Pathとして使用します。 298 // 299 // 返されるCmdのArgsフィールドは、コマンド名に続くargの要素から構築されます。 300 // したがって、argにはコマンド名自体を含めないでください。例えば、Command("echo", "hello")。 301 // Args[0]は常にnameで、解決されたPathではありません。 302 // 303 // Windowsでは、プロセスはコマンドライン全体を単一の文字列として受け取り、 304 // 自身でパースします。CommandはArgsを結合し、引用符で囲んで、 305 // CommandLineToArgvWを使用するアプリケーションと互換性のあるアルゴリズムで 306 // コマンドライン文字列にします(これが最も一般的な方法です)。注目すべき例外は、 307 // msiexec.exeとcmd.exe(したがって、すべてのバッチファイル)で、これらは異なる 308 // アンクォートアルゴリズムを持っています。これらまたは他の類似のケースでは、 309 // 自分で引用符を付けてSysProcAttr.CmdLineに完全なコマンドラインを提供し、 310 // Argsを空にすることができます。 311 func Command(name string, arg ...string) *Cmd 312 313 // CommandContextは [Command] と同様ですが、contextが含まれています。 314 // 315 // 提供されたcontextは、コマンドが自身で完了する前にcontextがdoneになった場合、 316 // プロセスを中断するために使用されます(cmd.Cancelまたは [os.Process.Kill] を呼び出す)。 317 // 318 // CommandContextは、コマンドのCancel関数をそのProcessのKillメソッドを呼び出すように設定し、 319 // WaitDelayは未設定のままにします。呼び出し元は、コマンドを開始する前にこれらのフィールドを 320 // 変更することでキャンセルの振る舞いを変更することができます。 321 func CommandContext(ctx context.Context, name string, arg ...string) *Cmd 322 323 // Stringは、cの人間が読める説明を返します。 324 // これはデバッグ専用です。 325 // 特に、シェルへの入力として使用するのには適していません。 326 // Stringの出力はGoのリリースによって異なる可能性があります。 327 func (c *Cmd) String() string 328 329 // Runは指定されたコマンドを開始し、その完了を待ちます。 330 // 331 // 返されるエラーは、コマンドが実行され、stdin、stdout、stderrのコピーに問題がなく、 332 // ゼロの終了ステータスで終了した場合にはnilです。 333 // 334 // コマンドが開始されるが正常に完了しない場合、エラーは 335 // [*ExitError] 型です。他の状況では他のエラータイプが返される可能性があります。 336 // 337 // 呼び出し元のgoroutineが [runtime.LockOSThread] でオペレーティングシステムのスレッドをロックし、 338 // 継承可能なOSレベルのスレッド状態(例えば、LinuxやPlan 9の名前空間)を変更した場合、 339 // 新しいプロセスは呼び出し元のスレッド状態を継承します。 340 func (c *Cmd) Run() error 341 342 // Startは指定されたコマンドを開始しますが、その完了を待ちません。 343 // 344 // Startが成功すると、c.Processフィールドが設定されます。 345 // 346 // Startの成功した呼び出しの後、関連するシステムリソースを解放するために 347 // [Cmd.Wait] メソッドを呼び出す必要があります。 348 func (c *Cmd) Start() error 349 350 // ExitErrorは、コマンドによる成功しない終了を報告します。 351 type ExitError struct { 352 *os.ProcessState 353 354 // Stderrは、標準エラーが他の方法で収集されていない場合、 355 // Cmd.Outputメソッドからの標準エラー出力の一部を保持します。 356 // 357 // エラー出力が長い場合、Stderrは出力のプレフィックスと 358 // サフィックスのみを含む可能性があり、中間部分は省略された 359 // バイト数に関するテキストに置き換えられます。 360 // 361 // Stderrはデバッグ用に提供され、エラーメッセージに含めるためです。 362 // 他のニーズを持つユーザーは、必要に応じてCmd.Stderrをリダイレクトしてください。 363 Stderr []byte 364 } 365 366 func (e *ExitError) Error() string 367 368 // Waitは、コマンドが終了するのを待ち、stdinへのコピーまたは 369 // stdoutまたはstderrからのコピーが完了するのを待ちます。 370 // 371 // コマンドは [Cmd.Start] によって開始されていなければなりません。 372 // 373 // 返されるエラーは、コマンドが実行され、stdin、stdout、stderrのコピーに問題がなく、 374 // ゼロの終了ステータスで終了した場合にはnilです。 375 // 376 // コマンドが実行に失敗するか、正常に完了しない場合、 377 // エラーは [*ExitError] 型です。I/O問題に対しては他のエラータイプが 378 // 返される可能性があります。 379 // 380 // c.Stdin、c.Stdout、c.Stderrのいずれかが [*os.File] でない場合、 381 // Waitは、プロセスへのまたはプロセスからの対応するI/Oループのコピーが 382 // 完了するのを待ちます。 383 // 384 // Waitは、Cmdに関連付けられたリソースを解放します。 385 func (c *Cmd) Wait() error 386 387 // Outputはコマンドを実行し、その標準出力を返します。 388 // 返されるエラーは通常、[*ExitError] 型です。 389 // c.Stderrがnilだった場合、Outputは [ExitError.Stderr] を設定します。 390 func (c *Cmd) Output() ([]byte, error) 391 392 // CombinedOutputはコマンドを実行し、その標準出力と標準エラーを結合したものを返します。 393 func (c *Cmd) CombinedOutput() ([]byte, error) 394 395 // StdinPipeは、コマンドが開始されたときにコマンドの標準入力に接続されるパイプを返します。 396 // パイプは、[Cmd.Wait] がコマンドの終了を確認した後、自動的に閉じられます。 397 // 呼び出し元は、パイプを早く閉じるためにCloseを呼び出すだけでよいです。 398 // 例えば、実行されるコマンドが標準入力が閉じるまで終了しない場合、呼び出し元はパイプを閉じる必要があります。 399 func (c *Cmd) StdinPipe() (io.WriteCloser, error) 400 401 // StdoutPipeは、コマンドが開始されたときにコマンドの標準出力に接続されるパイプを返します。 402 // 403 // [Cmd.Wait] は、コマンドの終了を確認した後にパイプを閉じるため、 404 // ほとんどの呼び出し元は自分でパイプを閉じる必要はありません。 405 // したがって、パイプからのすべての読み取りが完了する前にWaitを呼び出すことは誤りです。 406 // 同様の理由で、StdoutPipeを使用しているときに [Cmd.Run] を呼び出すことも誤りです。 407 // 一般的な使用法については、例を参照してください。 408 func (c *Cmd) StdoutPipe() (io.ReadCloser, error) 409 410 // StderrPipeは、コマンドが開始されたときにコマンドの標準エラーに接続されるパイプを返します。 411 // 412 // [Cmd.Wait] は、コマンドの終了を確認した後にパイプを閉じるため、 413 // ほとんどの呼び出し元は自分でパイプを閉じる必要はありません。 414 // したがって、パイプからのすべての読み取りが完了する前にWaitを呼び出すことは誤りです。 415 // 同様の理由で、StderrPipeを使用しているときに [Cmd.Run] を呼び出すことも誤りです。 416 // 一般的な使用法については、例を参照してください。 417 func (c *Cmd) StderrPipe() (io.ReadCloser, error) 418 419 // Environは、現在設定されている状態でコマンドが実行される環境のコピーを返します。 420 func (c *Cmd) Environ() []string 421 422 // ErrDotは、パスの検索が「.」がパスに含まれているために、 423 // 現在のディレクトリ内の実行可能ファイルに解決したことを示します。 424 // これは暗黙的または明示的に行われます。詳細はパッケージのドキュメンテーションを参照してください。 425 // 426 // このパッケージの関数はErrDotを直接返さないことに注意してください。 427 // コードはerr == ErrDotではなく、errors.Is(err, ErrDot)を使用して、 428 // 返されたエラーerrがこの条件によるものかどうかをテストする必要があります。 429 var ErrDot = errors.New("cannot run executable found relative to current directory")