現在実行中のファイルのディレクトリを取得するにはどうすればよいですか?


239

nodejsでは__dirnameを使用します。Golangでこれに相当するものは何ですか?

私はググってこの記事を見つけましたhttp://andrewbrookins.com/tech/golang-get-directory-of-the-current-file/。彼が以下のコードを使用する場所

_, filename, _, _ := runtime.Caller(1)
f, err := os.Open(path.Join(path.Dir(filename), "data.csv"))

しかし、それはGolangで行う正しい方法または慣用的な方法ですか?


これはあなたの質問の答えではありませんが、グローバル変数へのパスをキャッシュすることができます(実行中はファイルの場所を変更できません:))コードが実行されるたびにos.openを何度も実行しない
oguzalb

に渡すの0ではなく1、渡す必要がありruntime.Caller()ます。
fiatjaf 2017

4
runtime.Caller(0)のようなソースファイルのパスが表示されます$GOPATH/src/packagename/main.go。このスレッドの他の回答は、実行可能ファイルのパス(など$GOPATH/bin/packagename)を返そうとしています。
fiatjaf 2017

プログラムがファイルから実行されていると想定しています...
Flimzy

回答:


221

これはそれを行うはずです:

import (
    "fmt"
    "log"
    "os"
    "path/filepath"
)

func main() {
    dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
    if err != nil {
            log.Fatal(err)
    }
    fmt.Println(dir)
}

2
ここでエラーが発生する可能性はありますか?もしそうなら、好奇心から、エラーは何でしょうか?
ジェフエスカランテ2014年

4
私のために動作しませんplay.golang.org/p/c8fe-Zm_bH必ずしも腹筋のパスが含まれていませんos.Args [0] - 。
zupa 2015

5
os.Args [0]にabsパスが含まれていなくても、実際には機能します。プレイグラウンドの結果がサンドボックス内にあるため、期待した結果が得られないのはそのためです。
グスタボNiemeyer 2015

37
これは信頼できる方法はありません。osextの使用に関する回答をご覧ください。これは、さまざまなOSですべてのクライアントと連携する実装であったためです。この方法を使用してコードを実装しましたが、信頼性が低く、多くのユーザーが、この方法が実行可能ファイルの間違ったパスを選択することによって引き起こされるバグに不満を訴えています。
JD D

5
WindowsでGo 1.6を使用してemrahと同じ結果を得た(ソースファイルフォルダーではなく一時フォルダーのパスを取得した)。外部依存関係を使用せずにソースファイルのフォルダーのパスを取得するには、OPのコードを少し変更したバージョンを使用します_, currentFilePath, _, _ := runtime.Caller(0) dirpath := path.Dir(currentFilePath)(のruntime.Caller(0)代わりに注意runtime.Caller(1)
TanguyP

295

編集:Go 1.8(2017年2月リリース)以降、これを行うための推奨方法はos.Executable次のとおりです。

func Executable() (string, error)

Executableは、現在のプロセスを開始した実行可能ファイルのパス名を返します。パスが正しい実行可能ファイルを指しているという保証はありません。プロセスの開始にシンボリックリンクが使用された場合、オペレーティングシステムによっては、シンボリックリンクまたはそれが指しているパスになる可能性があります。安定した結果が必要な場合は、path / filepath.EvalSymlinksが役立ちます。

実行可能ファイルのディレクトリのみを取得するには、を使用できますpath/filepath.Dir

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    ex, err := os.Executable()
    if err != nil {
        panic(err)
    }
    exPath := filepath.Dir(ex)
    fmt.Println(exPath)
}

古い答え:

使えるはず os.Getwd

func Getwd() (pwd string, err error)

Getwdは、現在のディレクトリに対応するルート化されたパス名を返します。現在のディレクトリに複数のパスを介して到達できる場合(シンボリックリンクのため)、Getwdはそれらのいずれかを返すことがあります。

例えば:

package main

import (
    "fmt"
    "os"
)

func main() {
    pwd, err := os.Getwd()
    if err != nil {
        fmt.Println(err)
        os.Exit(1)
    }
    fmt.Println(pwd)
}

3
これは現在のプロセスの作業ディレクトリです。nodejsでは、process.cwd()nodejs.org/api/process.html#process_process_cwd
ekanna

2
わかりました、違いがわかります。(現在の作業ディレクトリではなく)runtime.Caller
ファイルシステム

3
「2017年2月リリース」?タイムマシーンが発明されたようで、未来からメンバーが投稿しています。将来のバージョンで信頼性の高いクロスプラットフォーム方式が提供されることを知ってうれしいですが、それまでの間、現在利用可能なソリューションに固執する必要があります。
ljgww 2017年

1
@ljgww申し訳ありませんが、デロリアンを持ち帰り、帰宅します。
Intermernet 2017年

1
ディレクトリ区切り文字としてスラッシュ(Unixスタイル)でのみ機能するpath/filepath.Dirため、path.Dirで編集されました。
Jocelyn 2017

63

パッケージosextを使用する

ExecutableFolder()現在実行中のプログラム実行可能ファイルが存在するフォルダーへの絶対パスを返す関数を提供しています(cronジョブに役立ちます)。クロスプラットフォームです。

オンライン文書

package main

import (
    "github.com/kardianos/osext"
    "fmt"
    "log"
)

func main() {
    folderPath, err := osext.ExecutableFolder()
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(folderPath)
}

13
これは、WindowsとLinuxの両方で期待される結果をもたらした唯一の答えです。
DannyB 2014年

3
go run main.goローカル開発で使用するまで、これは問題なく機能します。毎回事前に実行可能ファイルをビルドせずにそれを回避するのに最適な方法がわかりません。
Derek Dowling 2016年

1
申し訳ありませんが、で動作させる方法がわかりませんgo run。このバイナリは毎回一時フォルダに入れられます。
DobrosławŻybort

2
@DerekDowling a wayは、最初にを実行しgo install、次に実行しgo build -v *.go && ./mainます。は、-vどのファイルがビルドされているかを教えてくれます。一般的に、との間の時間差はgo rungo buildすでに実行している場合は許容できることがわかりましたgo install。PowerShellのWindowsユーザーの場合、コマンドは次のようになりますgo build -v {*}.go && ./main.exe
kumarharsh

これが戻るので$GOPATH/bin/、なぜ使用しないの$GOPATH/bin/ですか?
fiatjaf 2017

10
filepath.Abs("./")

Absはパスの絶対表現を返します。パスが絶対パスでない場合は、現在の作業ディレクトリと結合されて、絶対パスに変換されます。

コメントで述べたように、これは現在アクティブなディレクトリを返します。


8
これは、現在のファイルのディレクトリではなく、現在のディレクトリを返します。たとえば、実行可能ファイルが別のパスから呼び出された場合、これは異なります。
藤井

8

このように使用すると:

dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
    log.Fatal(err)
}
fmt.Println(dir)

GoLangなどのIDEを使用してプログラムを実行すると、/ tmpパスが取得されます。これは、実行可能ファイルが/ tmpから保存および実行されるためです。

現在の作業ディレクトリまたは「。」を取得するための最良の方法だと思います。は:

import(
  "os" 
  "fmt"
  "log"
)

func main() {
  dir, err := os.Getwd()
    if err != nil {
        log.Fatal(err)
    }
  fmt.Println(dir)
}

os.Getwd()関数は、現在の作業ディレクトリを返します。そしてそのすべては、外部ライブラリを使用せずに:D


これは正しくありません。これは、ファイルのディレクトリではなく、プロセスを実行しているユーザーの作業ディレクトリを返します。filepath.absを使用します。
PodTech.io

1
実行中の実行可能ファイルの作業ディレクトリを返します。次に、golandのようなIDEを使用していて、ビルドオプションに作業ディレクトリの設定がない場合、/ tmpから実行され、/ tmpの使用方法は何ですか???しかし、os.Getwd()を使用する場合.exeまたはelf実行可能ファイルのパスを返します。/ tmpではありません。
ビット

あなたが表示されますので、そのようなIDEでのデバッグの基本テンプレートを使用して@Bitは、はいあなたにそれを与え、そしてちょうど、「編集設定」フィル「出力ディレクトリを」ヒット「os.Argsを[0]」パスが何をしたいです
ϻαϻɾΣɀО -MaMrEzO

5

あなたは、パッケージを使用する場合osextをすることによってkardianosし、ローカルでテストする必要があり、デレク・ダウリングのようにコメントしました。

これは、ローカル開発用にgo run main.goで使用するまで問題なく機能します。毎回事前に実行可能ファイルをビルドせずにそれを回避するための最善の方法がわかりません。

これに対する解決策は、go runを使用する代わりにgorun.exeユーティリティを作成することです。gorun.exeユーティリティは、「go build」を使用してプロジェクトをコンパイルし、その直後に、プロジェクトの通常のディレクトリで実行します。

他のコンパイラでこの問題が発生し、これらのユーティリティはコンパイラに同梱されていないため、自分で作成していることに気付きました。特に、Cのようなツールでは、コンパイルしてリンクし、実行する必要がある(あまりにも多くの作業)ため、難解です。

私のgorun.exe(またはelf)のアイデアが気に入った場合は、すぐにgithubにアップロードします。

申し訳ありませんが、この回答はコメントを目的としていますが、評判がまだ高くないためコメントできません。

または、「go run」を変更して(この機能がまだない場合)、「go run -notemp」などのパラメーターを指定して、プログラムを一時ディレクトリ(または類似のディレクトリ)で実行しないようにすることもできます。ただし、複雑なパラメータよりも短いため、gorunまたは「gor」と入力することをお勧めします。Gorun.exeまたはgor.exeは、goコンパイラと同じディレクトリにインストールする必要があります。

gorun.exe(またはgor.exe)の実装は、他のコンパイラーで数行のコードで実行したので簡単です...(有名な最後の言葉;-)


3
「実行」とビルドされた実行可能ファイルの両方で動作するようにしたい場合は、_, callerFile, _, _ := runtime.Caller(0) executablePath := filepath.Dir(callerFile)代わりに単に使用してください
Jocelyn

@Jocelyn、あなたのコメントはとても素晴らしいので、あなたはそれを完全な答えにする必要があります!これは確かに私にトリックをもたらしました—私自身のセットアップでは、macOSに環境のローカルコピーがあります。これは主に構文エラー(およびいくつかのセマンティックエラー)をキャッチするために使用します。次に、Ubuntu Linuxで実行されるデプロイメントサーバーにコードを同期します。もちろん、環境は完全に異なります...したがって、テンプレート、構成ファイル、静的ファイルを適切にロードするためにファイルパスがどこにあるのかを理解する必要がありますファイルなど...
グウィネス・ルウェリン

4

os.Executablehttps : //tip.golang.org/pkg/os/#Executable

filepath.EvalSymlinkshttps : //golang.org/pkg/path/filepath/#EvalSymlinks

完全なデモ:

package main

import (
    "fmt"
    "os"
    "path/filepath"
)

func main() {
    var dirAbsPath string
    ex, err := os.Executable()
    if err == nil {
        dirAbsPath = filepath.Dir(ex)
        fmt.Println(dirAbsPath)
        return
    }

    exReal, err := filepath.EvalSymlinks(ex)
    if err != nil {
        panic(err)
    }
    dirAbsPath = filepath.Dir(exReal)
    fmt.Println(dirAbsPath)
}

4

時々これで十分です、最初の引数は常にファイルパスになります

package main

import (
    "fmt"
    "os"
)


func main() {
    fmt.Println(os.Args[0])

    // or
    dir, _ := os.Getwd()
    fmt.Println(dir)
}

0

グスタボ・ニーマイヤーの答えは素晴らしい。しかし、Windowsでは、ランタイムプロシージャは主に次のように別のディレクトリにあります。

"C:\Users\XXX\AppData\Local\Temp"

のように相対ファイルパス"/config/api.yaml"を使用すると、コードが存在するプロジェクトパスが使用されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.