kurumi-bioの雑記帳

プログラミング、パソコン、ペット、 犬、お出かけ

初心者のGo言語 -14- <Chdir,Chmod,Chown>

こんにちは、kurumi-bioです。18回目のブログです。
前回でfmtパッケージの学習が終わりました。

今回は第1回目のosパッケージ(標準ライブラリー)の学習です。

環境

OSバージョン:Windows11 Home 22H2
Go言語のバージョン:go version go1.19.4 windows/amd64

Chdir関数

func Chdir(dir string) error

Chdir は、現在の作業ディレクトリを名前付きディレクトリに変更します。エラーがある場合、タイプは *PathError になります。

<サンプルコード>ChdirSample.go

package main

import "fmt"
import "os"

func main() {
    e := os.Chdir("test")
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chdir Error: %v \n", e)
    } else {
        fmt.Println("success")
    }
}

<実行結果>

実行ディレクトリにtestフォルダが存在する状態で実行しました。
特に問題なく作業ディレクトリをtestに変更できました。

試しに存在しないディレクトリを指定すると、どうなるでしょうか。

<サンプルコード>ChdirSampleK1.go

package main

import "fmt"
import "os"

func main() {
    e := os.Chdir("none")
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chdir Error: %v \n", e)
    } else {
        fmt.Println("success")
    }
}

<実行結果>

chdir none: The system cannot find the file specified.
「指定されたフォルダが見つかりません。」というエラーになりました。

ちなみに、noneというファイルを作成して実行すると
chdir none: The directory name is invalid.
ディレクトリ名が無効です(ディレクトリ名ではありません)。」というエラーになります。

次にパスを含めて作業ディレクトリを変更してみます。
Windowsでは、パス階層の記述を\で行うことができますが、
Go言語ではどうでしょうか。

<サンプルコード>ChdirSampleK2.go

package main

import "fmt"
import "os"

func main() {
    e := os.Chdir("./test")
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chdir[/] Error: %v \n", e)
    } else {
        fmt.Println("success[/]")
    }
    e = os.Chdir("..")
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chdir[..] Error: %v \n", e)
    } else {
        fmt.Println("success[..]")
    }
    e = os.Chdir(".\\test")
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chdir[\\] Error: %v \n", e)
    } else {
        fmt.Println("success[\\]")
    }
}

<実行結果>

どちらの記述でもエラーにならずに作業ディレクトリの変更ができました。
/\の両方を一度に試したかったので、
testフォルダに変更⇒..で親フォルダ(元のフォルダ)に変更⇒再度testフォルダに変更 と、回りくどいことをやりました。

では、ドライブ指定はどうでしょうか試してみます。

<サンプルコード>ChdirSampleK3.go

package main

import "fmt"
import "os"

func main() {
    e := os.Chdir("C:/Windows")
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chdir Error: %v \n", e)
    } else {
        fmt.Println("success")
    }
}

<実行結果>

プロンプト表示を変えているので、実行ドライブがわからなくなっていますが、
Dドライブで実行して、CドライブのWindowsに作業ディレクトリの変更ができました。

Chmod関数

func Chmod(name string, mode FileMode) error

chmod は、指定されたファイルのモードを mode に変更します。ファイルがシンボリック リンクの場合、リンクのターゲットのモードが変更されます。エラーがある場合、タイプは *PathError になります。 オペレーティング システムに応じて、モード ビットの異なるサブセットが使用されます。 Unix では、モードの許可ビット、ModeSetuid、ModeSetgid、および ModeSticky が使用されます。 Windows では、モードの 0200 ビット (所有者が書き込み可能) のみが使用されます。ファイルの読み取り専用属性を設定するかクリアするかを制御します。他のビットは現在使用されていません。 Go 1.12 以前との>互換性のために、ゼロ以外のモードを使用してください。読み取り専用ファイルにはモード 0400 を使用し、読み取りと書き込みが可能なファイルにはモード 0600 を使用します。 プラン 9 では、モードの許可ビット、ModeAppend、ModeExclusive、および ModeTemporary が使用されます。

<サンプルコード>ChmodSample.go

package main

import "fmt"
import "os"

func main() {
    e := os.Chmod("0200.txt", 0200)
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chdir Error: %v \n", e)
    } else {
        fmt.Println("success")
    }

    e = os.Chmod("0400.txt", 0400)
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chdir Error: %v \n", e)
    } else {
        fmt.Println("success")
    }

    e = os.Chmod("0600.txt", 0600)
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chdir Error: %v \n", e)
    } else {
        fmt.Println("success")
    }
}

<実行結果>

0400だけ読み取り専用になっていて、 0200と0600は同じです。
これは、Unixのアクセス権限の指定方法でWindowsのアクセス権を設定しているためで、
2(書込み許可)または6(書込み許可+読込許可)を指定すると、
書き込み権があるので読み取り専用になりません。
また、2(書込み許可)を指定した場合は、読込許可がないので参照不可なのですが、
Windowsではそのようなアクセス権がないため、
結果として2と6が同じになっていると思います。

※) Unixのアクセス権
Unixでは、権限を所有者グループその他の単位で指定できます。
そのため、os.Chmodのmode引数で渡している数値は、
1桁目がその他、2桁目がグループ、3桁目が所有者に対するアクセス権限の設定になります。 また、Windowsでは、3桁目の所有者に対するアクセス権設定のみが可能となっています。

各桁の数値ですが、アクセス権を指定しており、
その値は下記のテーブルの通りとなります。
例えば、読み書き可能にする場合は、4+2=6で、6を指定することになります。

数値 内容
4 読込み許可
2 書込み許可
1 実行許可

2023年3月19日 追記 アクセス権を数値文字列で指定する方法を記載しましたので参考にしてください。 kurumi-bio.hatenablog.com

Chown関数

func Chown(name string, uid, gid int) error

Chown は、指定されたファイルの数値 uid と gid を変更します。ファイルがシンボリック リンクの場合、リンク先の uid と gid が変更されます。 -1 の uid または gid は、その値を変更しないことを意味します。エラーがある場合、タイプは PathError になります。 Windows または Plan 9 では、Chown は常に PathError でラップされた syscall.EWINDOWS または EPLAN9 エラーを返します。

<サンプルコード>ChownSample.go

package main

import "fmt"
import "os"

func main() {
    e := os.Chown("test.txt", 1, 1)
    if e != nil {
        fmt.Fprintf(os.Stderr, "Chown Error: %v \n", e)
    } else {
        fmt.Println("success")
    }
}

<実行結果>

説明に記載されている通りで、 chown test.txt: not supported by windowsWindowsではサポートされていません。」のエラーが発生して何も変更できませんでした。