パスからファイル、ディレクトリ、リンクで処理を分ける

与えられたパスがファイルなのか、ディレクトリなのか、リンクなのかを調べるには、os.Stat(path string)でまずFileInfoを得ます。それから、FileInfo.Modeにos.Symlinkのフラグが立っていればリンク、ディレクトリの場合はIsDirで調べられます。

リンクからリンク元のパスを得るには、os.Readlink(path string)で調べられます。

package main
import (
	"fmt"
	"io/ioutil"
	"os"
)
func PrintFileContent(f *os.File) {
	src, _ := ioutil.ReadAll(f)
	f.Close()
	fmt.Printf("%q\n", src)
}

func main() {
	args := os.Args[1:]
	if 1 != len(args) {
		fmt.Fprintf(os.Stderr, "usage:%s FILE|DIR|LINK\n", os.Args[0])
		os.Exit(1)
	}
	finfo, err := os.Stat(args[0])
	if err != nil {
		fmt.Fprintf(os.Stderr, "%v", err)
		os.Exit(1)
	}
	if finfo.Mode()&os.ModeSymlink != 0 {
		path, err := os.Readlink(args[0])
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v", err)
			os.Exit(1)
		}
		finfo, err = os.Stat(path)
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v", err)
			os.Exit(1)
		}
		args[0] = path
	}
	if !finfo.IsDir() {
		f, err := os.Open(args[0])
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v", err)
			os.Exit(1)
		}
		PrintFileContent(f)
		return
	} else {
		list, err := ioutil.ReadDir(args[0])
		if err != nil {
			fmt.Fprintf(os.Stderr, "%v", err)
			os.Exit(1)
		}
		for _, finfo := range list {
			if finfo.IsDir() {
				continue
			}
			path := fmt.Sprintf("%s%c%s", args[0], os.PathSeparator, finfo.Name())
			f, err := os.Open(path)
			if err != nil {
				fmt.Fprintf(os.Stderr, "%v", err)
				os.Exit(1)
			}
			PrintFileContent(f)
		}
	}
}