Know About Files and Directories in Go

Files and Directories

This topic will let us know how to use the Go to work with the various types of files and directories of a filesystem for developing real system utilities.

This Topic will let us to know the following process:

  • The Go package will help us manipulate directories and file processing command-line arguments and options easily using the flag package(标记包)
  • Developing a version of the which(1) command-line utility in Go.
  • Developing a version of the pwd(1) command-line in Go
  • Deleting and renaming files and directories
  • Traversing directory trees easily
  • Writing a version of the find(1) utility in Go
  • Duplicate a directory structure in another place.

Useful Go packages

  • the os package : allow you manipulate files and directories as entities package
  • The flag package : lets you define and process your own flags and manipulate the command-line  arguments of a Go program.
  • The filepath package (extremly handy) : allow you traverse entire directory structures in an easy way (By the filepath.Walk function)

Command-line arguments revisited

You can use the flag package work efficiently with multiple command-line arguments and options using if statements.

Remembering that the flag package is a standard Go package and that you do not have to search for the functionality of a flag elsewhereis extremely important.

The flag package

  • Help us does the dirty work of parsing command-line arguments and options
  • Needn't writting complicated and perplexing Go Code
  • Supports various types of parameters,including strings, integers, and Boolean.(help us to save time  for perform any data type conversions.

Show my code:

The usingFlag.go program illustrate the use of the flag package.

[maxwell@MaxwellDBA theflagpackage]$ 
[maxwell@MaxwellDBA theflagpackage]$ vim usingFlag.go
[maxwell@MaxwellDBA theflagpackage]$ go run usingFlag.go
-o: false
-c: false
-K: 0
[maxwell@MaxwellDBA theflagpackage]$ go run usingFlag.go -o a b
-o: true
-c: false
-K: 0
0 : a
1 : b
[maxwell@MaxwellDBA theflagpackage]$ cat usingFlag.go
package main

import (
   "flag"
   "fmt"
)


func main(){
   minus0 := flag.Bool("o", false, "o")
   minusC := flag.Bool("c", false, "c")
   minusK := flag.Int("k", 0, "an int")

   flag.Parse()

   fmt.Println("-o:", *minus0)
   fmt.Println("-c:", *minusC)
   fmt.Println("-K:", *minusK)

   for index, val := range flag.Args(){
         fmt.Println(index, ":", val)
   }
}
[maxwell@MaxwellDBA theflagpackage]$ 
[maxwell@MaxwellDBA theflagpackage]$ go run usingFlag.go -k
flag needs an argument: -k
Usage of /tmp/go-build888547157/b001/exe/usingFlag:
  -c    c
  -k int
        an int
  -o    o
exit status 2
[maxwell@MaxwellDBA theflagpackage]$ 

  • below program defined the flag: -o,-c,and -k. the first two are Boolean flags , the -k flags requires an integer value, which can be given as -k=123.
  • flag.Args() allow you to access the unused command-line arguments of the program.
  • if you forget to type the value of a command-line option(-k) or the provided value is of the wrong type, you will get the following messages and the program will terminate.

Dealing with directories

Directories allow you to create aa structure and store your files in a way easily for you to organize and search for them.

In reality, directories are entries on a filesystem that contain lists of other files and directories

Inodes , which are data structures that hold information about files and directories.

directories are implemented as lists of names assigned to inodes.As a result, a directory contains an entry for itself, its parent directory, and each of its children, which among other things can be regular files or other directories:

What you should remember is that an inode holds metadata about a file,not the actual data of a file.

About symbolic links

  • Symbolic links are pointers to files or directories, which are resolved at the time of access.
  • Symbolic links (also called soft links)

The program symbLink.go allow you to check whether a path or file is a symbolic link or not.

[maxwell@MaxwellDBA symboliclinks]$ su - 
Password: 
Last login: Tue Dec 13 19:57:07 CST 2022 from 223.71.135.190 on pts/1
Last failed login: Tue Dec 13 21:04:50 CST 2022 on pts/1
There was 1 failed login attempt since the last successful login.
[root@MaxwellDBA ~]# ln -s /home/maxwell/goproject/symboliclinks /symboliclinks
[root@MaxwellDBA ~]# su - maxwell
Last login: Tue Dec 13 19:57:24 CST 2022 on pts/1
[maxwell@MaxwellDBA ~]$

[maxwell@MaxwellDBA symboliclinks]$ ls -ltr
total 4
-rw-rw-r-- 1 maxwell maxwell 542 Dec 13 21:01 symbLink.go
[maxwell@MaxwellDBA symboliclinks]$ go run symbLink.go /symboliclinks
/symboliclinks is a symbolic link
Path: /home/maxwell/goproject/symboliclinks
[maxwell@MaxwellDBA symboliclinks]$ cat symbLink.go
package main

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


func main() {
   arguments := os.Args
   if len(arguments) == 1 {
         fmt.Println("Please provide an argument!")
         os.Exit(1)
   }
   filename := arguments[1]
   fileinfo, err := os.Lstat(filename)
   if err != nil {
        fmt.Println(err)
        os.Exit(1)
   }

   if fileinfo.Mode()&os.ModeSymlink != 0 {
          fmt.Println(filename, "is a symbolic link")
          realpath, err := filepath.EvalSymlinks(filename)
          if err == nil {
               fmt.Println("Path:", realpath)
          }

   }
}
[maxwell@MaxwellDBA symboliclinks]$ 

Implementing the pwd(1) command

The pwd(1) command-line utility is pretty simplistic

you get the full path of a file or a directory  that resides in the same directory as the script that is being executed.

The -P command-line option, which resolves all symbolic links and prints the physical current working directory.

[maxwell@MaxwellDBA pwd]$ vim pwd.go   
[maxwell@MaxwellDBA pwd]$ go run pwd.go
/home/maxwell/goproject/pwd
[maxwell@MaxwellDBA pwd]$ go run pwd.go -P
/home/maxwell/goproject/pwd
[maxwell@MaxwellDBA pwd]$ cat pwd.go
package main

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


func main() {
   arguments := os.Args

   pwd, err := os.Getwd()
   if err == nil {
          fmt.Println(pwd)
   } else {
        fmt.Println("Error:", err)
   }

   if len(arguments) == 1 {
         return
   }

   if arguments[1] != "-P" {
      return
   }

   fileinfo, err := os.Lstat(pwd)

   if fileinfo.Mode()&os.ModeSymlink != 0 {

          realpath, err := filepath.EvalSymlinks(pwd)
          if err == nil {
               fmt.Println(realpath)
          }
   }
}
[maxwell@MaxwellDBA pwd]$ 

Developing the which(1) utility in Go

[maxwell@MaxwellDBA which]$ echo $PATH
/home/maxwell/.local/bin:/home/maxwell/bin:/usr/share/Modules/bin:/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin
[maxwell@MaxwellDBA which]$ which ls
alias ls='ls --color=auto'
        /usr/bin/ls
[maxwell@MaxwellDBA which]$ which -a ls
alias ls='ls --color=auto'
        /usr/bin/ls
[maxwell@MaxwellDBA which]$ 

Note that go run prints out nonzero exit codes.

[maxwell@MaxwellDBA which]$ vim which.go      
[maxwell@MaxwellDBA which]$ go run which.go ls
/usr/bin/ls
[maxwell@MaxwellDBA which]$ go run which.go -s ls
[maxwell@MaxwellDBA which]$ echo $?
0
[maxwell@MaxwellDBA which]$ go run which.go -s ls123123
exit status 1
[maxwell@MaxwellDBA which]$ echo $?
1
[maxwell@MaxwellDBA which]$ go run which.go -a ls
/usr/bin/ls
[maxwell@MaxwellDBA which]$ cat which.go
package main

import (
   "flag"
   "fmt"
   "os"
   "strings"
)

//The strings package is needed in order to split the contents of the PATH variable after you read it.
 //deal with the use of the flag package

func main() {
   minusA := flag.Bool("a", false, "a")
   minusS := flag.Bool("s", false, "s")

   flag.Parse()
   flags := flag.Args()
   if len(flags) == 0 {
         fmt.Println("Please provide an argument!")
         os.Exit(1)
   }
   file := flags[0]
   fountIt := false

   //reads the PATH shell environment variable in order to split it and use it.
   path := os.Getenv("PATH")
   pathSlice := strings.Split(path, ":")
   for _, directory := range pathSlice {
         fullPath := directory + "/" + file
         fileInfo, err := os.Stat(fullPath)
         if err == nil {
               mode := fileInfo.Mode()
               if mode.IsRegular() {
                    if mode&0111 != 0 {
                          fountIt = true
                          if *minusS == true {
                                os.Exit(0)
                          }
                          if *minusA == true {
                                fmt.Println(fullPath)
                          } else {
                                fmt.Println(fullPath)
                                os.Exit(0)
                          }
                    }
               }
         }
   }
   if fountIt == false {
         os.Exit(1)
   }
}
[maxwell@MaxwellDBA which]$ 
  • The call to os.Stat() tell whether the file we are looking for actually exists or not.
  • The mode.IsRegular() function checks wheter the file is a regular file or not
  • The which.go program performs a test to find out whether the file that was found is indeed an executable file.
  • the if mode&0111 != 0 statement verifies that the file is actually an executable file using a binary operation.

Printing the permission bits of a file or directory

With the help of the ls(1) command, you can find out the permissions of a file:

[maxwell@MaxwellDBA which]$ ls -l /bin/ls
-rwxr-xr-x 1 root root 143224 Jul 14  2021 /bin/ls
[maxwell@MaxwellDBA which]$ 

we will look at how to print the permissions of a file or directory using Go:

[maxwell@MaxwellDBA permissions]$ vim permissions.go
[maxwell@MaxwellDBA permissions]$ go run permissions.go /bin/ls
/bin/ls: -rwxr-xr-x
[maxwell@MaxwellDBA permissions]$ go run permissions.go /usr
/usr: drwxr-xr-x
[maxwell@MaxwellDBA permissions]$ go run permissions.go  /goproject
Error: stat /goproject: no such file or directory
exit status 1
[maxwell@MaxwellDBA permissions]$
[maxwell@MaxwellDBA permissions]$ cat permissions.go
package main

import (
  "fmt"
  "os"
)

func main() {
   arguments := os.Args
   if len(arguments) == 1 {
         fmt.Println("Please provide an argument!")
         os.Exit(1)
   }

   file := arguments[1]

   info, err := os.Stat(file)
   if err != nil {
         fmt.Println("Error:", err)
         os.Exit(1)
   }
   mode := info.Mode()
   fmt.Print(file, ": ", mode, "\n")
}
[maxwell@MaxwellDBA permissions]$ 

Dealing with files in Go

Deleting a file

We will illustrate how to delete files and directories using the os.Remove() Go function.

When testing programs that delete files and directories be extra careful and use common sense!

[maxwell@MaxwellDBA rm]$ vim rm.go
[maxwell@MaxwellDBA rm]$ go run rm.go 123
remove 123: no such file or directory
[maxwell@MaxwellDBA rm]$ ls -ltr /tmp/AlTest1.err
ls: cannot access '/tmp/AlTest1.err': No such file or directory
[maxwell@MaxwellDBA rm]
[maxwell@MaxwellDBA rm]$ go run rm.go /tmp/
remove /tmp/: permission denied
[maxwell@MaxwellDBA rm]$ mkdir test
[maxwell@MaxwellDBA rm]$ cd test
[maxwell@MaxwellDBA test]$ touch t1
[maxwell@MaxwellDBA test]$ touch t2
[maxwell@MaxwellDBA test]$ cd ..
[maxwell@MaxwellDBA rm]$ pwd
/home/maxwell/goproject/rm
[maxwell@MaxwellDBA rm]$ cd test
[maxwell@MaxwellDBA test]$ pwd
/home/maxwell/goproject/rm/test
[maxwell@MaxwellDBA test]$ cd ..
[maxwell@MaxwellDBA rm]$ go run rm.go test
remove test: directory not empty
[maxwell@MaxwellDBA rm]$ cat rm.go
package main
import (
   "fmt"
   "os"
)


func main() {
   arguments := os.Args
   if len(arguments) == 1 {
         fmt.Println("Please provide an argument!")
         os.Exit(1)
   }

   file := arguments[1]
   err := os.Remove(file)
   if err != nil {
         fmt.Println(err)
         return
   }
}
[maxwell@MaxwellDBA rm]$ 

Renaming and moving files

we will show you how to rename and move a file using Go code.

The same code can be used for renaming or moving directories.

rename.go is only allowed to work with files.

When developing systems software, you have to deal with all the details or the details will reveal themselves as bugs when least expected! Extensive testing will allow you to find the details you missed and correct them.

[maxwell@MaxwellDBA rename]$ vim rename.go
[maxwell@MaxwellDBA rename]$ go run rename.go newFILE regExpFind.go
Destination file already exists!
exit status 1
[maxwell@MaxwellDBA rename]$ go run rename.go -overwrite newFILE regExpFind.go
[maxwell@MaxwellDBA rename]$ cat rename.go
package main

import (

  "flag"
  "fmt"
  "os"
  "path/filepath"
)


func main(){
   minusOverwrite := flag.Bool("overwrite", false, "overwrite")

   flag.Parse()
   flags := flag.Args()

   if len(flags) < 2 {
         fmt.Println("Please provide two arguments!")
         os.Exit(1)
   }
   source := flags[0]
   destination := flags[1]
   fileInfo, err := os.Stat(source)
   if err == nil {
         mode := fileInfo.Mode()
         if mode.IsRegular() == false {
               fmt.Println("Sorry, we only support regular files as source!")
               os.Exit(1)
         }
    } else {
         fmt.Println("Error reading:", source)
         os.Exit(1)
   }

   newDestination := destination
   destInfo, err := os.Stat(destination)
   if err == nil {
         mode := destInfo.Mode()
         if mode.IsDir() {
              justTheName := filepath.Base(source)
              newDestination = destination + "/" + justTheName
        }
   }

   destination = newDestination
   destInfo, err = os.Stat(destination)
   if err == nil {
         if *minusOverwrite == false {
               fmt.Println("Destination file already exists!")
               os.Exit(1)
        }
   }

   err = os.Rename(source, destination)
   if err != nil {
        fmt.Println(err)
        os.Exit(1)
   }
}
[maxwell@MaxwellDBA rename]$ 

Developing find(1) in Go

Traversing a directory tree

find(1) needs to support is being able to visit all files and sub directories staring from a given directory .

[maxwell@MaxwellDBA traversing]$ vim traverse.go
[maxwell@MaxwellDBA traversing]$ pwd
/home/maxwell/goproject/traversing
[maxwell@MaxwellDBA traversing]$
[maxwell@MaxwellDBA traversing]$ go run traverse.go ~/goproject
/home/maxwell/goproject
/home/maxwell/goproject/AdvancedGoFeatures
/home/maxwell/goproject/AdvancedGoFeatures/funErr.go
/home/maxwell/goproject/AdvancedGoFeatures/logging.go
/home/maxwell/goproject/Interfaces
/home/maxwell/goproject/Interfaces/interfaces.go
/home/maxwell/goproject/Patternmatchingandregualrexpressions
/home/maxwell/goproject/Patternmatchingandregualrexpressions/readColumn.go
/home/maxwell/goproject/Patternmatchingandregualrexpressions/regExp.go
/home/maxwell/goproject/Reflection
/home/maxwell/goproject/Reflection/reflection.go
/home/maxwell/goproject/aFile
/home/maxwell/goproject/aSimplePackage
/home/maxwell/goproject/aSimplePackage/aSimplePackage.go
/home/maxwell/goproject/addCLA.go
/home/maxwell/goproject/addCLAImproved.go
/home/maxwell/goproject/cla
/home/maxwell/goproject/cla.go
/home/maxwell/goproject/convertinganarrayintoamap
/home/maxwell/goproject/convertinganarrayintoamap/array2map.go
/home/maxwell/goproject/creatingsummaries
/home/maxwell/goproject/creatingsummaries/summary.go
/home/maxwell/goproject/defer.go
/home/maxwell/goproject/findandreplace
/home/maxwell/goproject/findandreplace/findReplace.go
/home/maxwell/goproject/findingthenumberofoccurrences
/home/maxwell/goproject/findingthenumberofoccurrences/occurrences.go
/home/maxwell/goproject/functions.go
/home/maxwell/goproject/garbagecollection
/home/maxwell/goproject/garbagecollection/garbageCol.go
/home/maxwell/goproject/godatastructure
/home/maxwell/goproject/godatastructure/arrays.go
/home/maxwell/goproject/godatastructure/breakMe.go
/home/maxwell/goproject/godatastructure/maps.go
/home/maxwell/goproject/godatastructure/slices.go
/home/maxwell/goproject/hashtable
/home/maxwell/goproject/hashtable/hash.go
/home/maxwell/goproject/hashtable/hash1.go
/home/maxwell/goproject/hw
/home/maxwell/goproject/hw.go
/home/maxwell/goproject/linkedlist
/home/maxwell/goproject/linkedlist/linkedList.go
/home/maxwell/goproject/parameter.go
/home/maxwell/goproject/permissions
/home/maxwell/goproject/permissions/permissions.go
/home/maxwell/goproject/pointers.go
/home/maxwell/goproject/pwd
/home/maxwell/goproject/pwd/pwd.go
/home/maxwell/goproject/randomnumber
/home/maxwell/goproject/randomnumber/random.go
/home/maxwell/goproject/rename
/home/maxwell/goproject/rename/regExpFind.go
/home/maxwell/goproject/rename/rename.go
/home/maxwell/goproject/rename/rename_bkp.go
/home/maxwell/goproject/rm
/home/maxwell/goproject/rm/rm.go
/home/maxwell/goproject/rm/test
/home/maxwell/goproject/rm/test/t1
/home/maxwell/goproject/rm/test/t2
/home/maxwell/goproject/runTime
/home/maxwell/goproject/runTime/runTime.go
/home/maxwell/goproject/structures
/home/maxwell/goproject/structures/goStructures.go
/home/maxwell/goproject/structures/goStructuresusex.go
/home/maxwell/goproject/symboliclinks
/home/maxwell/goproject/symboliclinks/symbLink.go
/home/maxwell/goproject/theflagpackage
/home/maxwell/goproject/theflagpackage/usingFlag.go
/home/maxwell/goproject/thesortslicefunction
/home/maxwell/goproject/thesortslicefunction/sortSlice.go
/home/maxwell/goproject/traversing
/home/maxwell/goproject/traversing/traverse.go
/home/maxwell/goproject/trees
/home/maxwell/goproject/trees/tree.go
/home/maxwell/goproject/unglyHW
/home/maxwell/goproject/unglyHW.go
/home/maxwell/goproject/unreachablecode
/home/maxwell/goproject/unreachablecode/cannotReach.go
/home/maxwell/goproject/unsafecode
/home/maxwell/goproject/unsafecode/unsafe.go
/home/maxwell/goproject/which
/home/maxwell/goproject/which/which.go
[maxwell@MaxwellDBA traversing]$ 
[maxwell@MaxwellDBA traversing]$ cat traverse.go
package main


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

func walkFunction(path string, info os.FileInfo, err error) error {
   _, err = os.Stat(path)
   if err != nil {
        return err
   }

   fmt.Println(path)
   return nil
}

func main(){
   arguments := os.Args
   if len(arguments) == 1 {
         fmt.Println("Not enough arguments!")
         os.Exit(1)
   }

   Path := arguments[1]
   err := filepath.Walk(Path, walkFunction)
   if err != nil {
         fmt.Println(err)
         os.Exit(1)
   }
}
[maxwell@MaxwellDBA traversing]$

Visiting directories only!

The program traverseDir.go  wiil visit everything but only print the directory names.

[maxwell@MaxwellDBA traversing]$ vim traverseDir.go               
[maxwell@MaxwellDBA traversing]$ go run traverseDir.go ~/goproject
/home/maxwell/goproject
/home/maxwell/goproject/AdvancedGoFeatures
/home/maxwell/goproject/Interfaces
/home/maxwell/goproject/Patternmatchingandregualrexpressions
/home/maxwell/goproject/Reflection
/home/maxwell/goproject/aSimplePackage
/home/maxwell/goproject/convertinganarrayintoamap
/home/maxwell/goproject/creatingsummaries
/home/maxwell/goproject/findandreplace
/home/maxwell/goproject/findingthenumberofoccurrences
/home/maxwell/goproject/garbagecollection
/home/maxwell/goproject/godatastructure
/home/maxwell/goproject/hashtable
/home/maxwell/goproject/linkedlist
/home/maxwell/goproject/permissions
/home/maxwell/goproject/pwd
/home/maxwell/goproject/randomnumber
/home/maxwell/goproject/rename
/home/maxwell/goproject/rm
/home/maxwell/goproject/rm/test
/home/maxwell/goproject/runTime
/home/maxwell/goproject/structures
/home/maxwell/goproject/symboliclinks
/home/maxwell/goproject/theflagpackage
/home/maxwell/goproject/thesortslicefunction
/home/maxwell/goproject/traversing
/home/maxwell/goproject/trees
/home/maxwell/goproject/unreachablecode
/home/maxwell/goproject/unsafecode
/home/maxwell/goproject/which
[maxwell@MaxwellDBA traversing]$ cat traverseDir.go
package main


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

func walkFunction(path string, info os.FileInfo, err error) error {
   fileInfo, err:= os.Stat(path)
   if err != nil {
        return err
   }

   mode := fileInfo.Mode()
   if mode.IsDir() {
         fmt.Println(path)
   }
   return nil
}

func main(){
   arguments := os.Args
   if len(arguments) == 1 {
         fmt.Println("Not enough arguments!")
         os.Exit(1)
   }

   Path := arguments[1]
   err := filepath.Walk(Path, walkFunction)
   if err != nil {
         fmt.Println(err)
         os.Exit(1)
   }
}
[maxwell@MaxwellDBA traversing]$ 

The first version of find(1)

[maxwell@MaxwellDBA traversing]$ vim find.go               
[maxwell@MaxwellDBA traversing]$ go run find.go ~/goproject
/home/maxwell/goproject
/home/maxwell/goproject/AdvancedGoFeatures
/home/maxwell/goproject/AdvancedGoFeatures/funErr.go
/home/maxwell/goproject/AdvancedGoFeatures/logging.go
/home/maxwell/goproject/Interfaces
/home/maxwell/goproject/Interfaces/interfaces.go
/home/maxwell/goproject/Patternmatchingandregualrexpressions
/home/maxwell/goproject/Patternmatchingandregualrexpressions/readColumn.go
/home/maxwell/goproject/Patternmatchingandregualrexpressions/regExp.go
/home/maxwell/goproject/Reflection
/home/maxwell/goproject/Reflection/reflection.go
/home/maxwell/goproject/aFile
/home/maxwell/goproject/aSimplePackage
/home/maxwell/goproject/aSimplePackage/aSimplePackage.go
/home/maxwell/goproject/addCLA.go
/home/maxwell/goproject/addCLAImproved.go
/home/maxwell/goproject/cla
/home/maxwell/goproject/cla.go
/home/maxwell/goproject/convertinganarrayintoamap
[maxwell@MaxwellDBA traversing]$ cat find.go
package main


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

func walkFunction(path string, info os.FileInfo, err error) error {
   fileInfo, err := os.Stat(path)
   if err != nil {
        return err
   }

   mode := fileInfo.Mode()
   if mode.IsDir() || mode.IsRegular(){
         fmt.Println(path)
   }
   return nil
}

func main(){
   flag.Parse()
   flags := flag.Args()

   if len(flags) == 0 {
         fmt.Println("Not enough arguments!")
         os.Exit(1)
   }

   Path := flags[0]
   err := filepath.Walk(Path, walkFunction)
   if err != nil {
         fmt.Println(err)
         os.Exit(1)
   }
}
[maxwell@MaxwellDBA traversing]$ 

Adding some command-line options

The improvedFind.go program is a real system tool that you can use on your own Unix machines.

The supported flags will be the following:

-s: This is for printing socket files

-p: This is for printing pipes

-sl: This is for printing symbolic links

-d: This is for printing directories

-f : This is for printing files

[maxwell@MaxwellDBA improvedFind]$ ln -s /home/maxwell/goproject/ aLink
[maxwell@MaxwellDBA improvedFind]$ pwd
/home/maxwell/goproject/improvedFind
[maxwell@MaxwellDBA improvedFind]$ ls -ltr
total 4
-rw-rw-r-- 1 maxwell maxwell 1563 Dec 14 21:58 improvedFind.go
lrwxrwxrwx 1 maxwell maxwell   24 Dec 14 22:08 aLink -> /home/maxwell/goproject/
[maxwell@MaxwellDBA improvedFind]$ go run improvedFind.go -sl ~/goproject/
/home/maxwell/goproject/improvedFind/aLink
[maxwell@MaxwellDBA improvedFind]$ go run improvedFind.go -d ~/goproject/ 
/home/maxwell/goproject/
/home/maxwell/goproject/AdvancedGoFeatures
/home/maxwell/goproject/Interfaces
/home/maxwell/goproject/Patternmatchingandregualrexpressions
/home/maxwell/goproject/Reflection
/home/maxwell/goproject/aSimplePackage
/home/maxwell/goproject/convertinganarrayintoamap
/home/maxwell/goproject/creatingsummaries
/home/maxwell/goproject/findandreplace
/home/maxwell/goproject/findingthenumberofoccurrences
/home/maxwell/goproject/garbagecollection
/home/maxwell/goproject/godatastructure
/home/maxwell/goproject/hashtable
/home/maxwell/goproject/improvedFind
/home/maxwell/goproject/improvedFind/aLink
/home/maxwell/goproject/linkedlist
/home/maxwell/goproject/permissions
/home/maxwell/goproject/pwd
/home/maxwell/goproject/randomnumber
/home/maxwell/goproject/rename
/home/maxwell/goproject/rm
/home/maxwell/goproject/rm/test
/home/maxwell/goproject/runTime
/home/maxwell/goproject/structures
/home/maxwell/goproject/symboliclinks
/home/maxwell/goproject/theflagpackage
/home/maxwell/goproject/thesortslicefunction
/home/maxwell/goproject/traversing
/home/maxwell/goproject/trees
/home/maxwell/goproject/unreachablecode
/home/maxwell/goproject/unsafecode
/home/maxwell/goproject/which
[maxwell@MaxwellDBA improvedFind]$ go run improvedFind.go -sl ~/goproject/
/home/maxwell/goproject/improvedFind/aLink
[maxwell@MaxwellDBA improvedFind]$ 
[maxwell@MaxwellDBA improvedFind]$ cat improvedFind.go
package main

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

func main() {

   minusS := flag.Bool("s",false,"Sockets")
   minusP := flag.Bool("p",false, "Pipes")
   minusSL := flag.Bool("sl",false,"Symbolic Links")
   minusD := flag.Bool("d", false,"Directories")
   minusF := flag.Bool("f", false, "Files")

   flag.Parse()
   flags := flag.Args()

   printAll := false
   if *minusS && *minusP && *minusSL && *minusD && *minusF {
         printAll = true
   }

   if !(*minusS || *minusP || *minusSL || *minusD || *minusF){
        printAll = true
   }

   if len(flags) == 0 {
         fmt.Println("Not enough arguments!")
         os.Exit(1)
   }

   Path := flags[0]

   walkFunction := func(path string, info os.FileInfo, err error) error {
           fileInfo, err := os.Stat(path)
           if err != nil {
                return err
           }

           if printAll {
                 fmt.Println(path)
                 return nil
           }

           mode := fileInfo.Mode()
           if mode.IsRegular() && *minusF {
                 fmt.Println(path)
                 return nil
           }

           if mode.IsDir() && *minusD {
                 fmt.Println(path)
                 return nil
           }

           fileInfo, _ = os.Lstat(path)
           if fileInfo.Mode()&os.ModeSymlink != 0 {
                 if *minusSL {
                       fmt.Println(path)
                       return nil
                }
           }

           if fileInfo.Mode()&os.ModeNamedPipe != 0 {
                 if *minusP {
                      fmt.Println(path)
                      return nil
                }
          }

          if fileInfo.Mode()&os.ModeSocket != 0 {
                if *minusS {
                      fmt.Println(path)
                      return nil
                }
          }

          return nil
   }

   err := filepath.Walk(Path, walkFunction)
   if err != nil {
         fmt.Println(err)
         os.Exit(1)
   }

 }
[maxwell@MaxwellDBA improvedFind]$ 

Excluding filenames from the find output

Note that this version of the program will not support regular expressions and will only exclude filenames that are an exact match.

The program excludeNames() , that deals with filename exclusion and the addition of the -x flag, which is used for setting the filename you want to exclude from the output.

[maxwell@MaxwellDBA improvedFind]$ pwd
/home/maxwell/goproject/improvedFind
[maxwell@MaxwellDBA improvedFind]$ go run excludeFind.go  ~/goproject/improvedFind/
/home/maxwell/goproject/improvedFind/
/home/maxwell/goproject/improvedFind/aLink
/home/maxwell/goproject/improvedFind/dT.py
/home/maxwell/goproject/improvedFind/excludeFind.go
/home/maxwell/goproject/improvedFind/improvedFind.go
[maxwell@MaxwellDBA improvedFind]$ go run excludeFind.go -x=dT.py ~/goproject/improvedFind/
/home/maxwell/goproject/improvedFind/
/home/maxwell/goproject/improvedFind/aLink
/home/maxwell/goproject/improvedFind/excludeFind.go
/home/maxwell/goproject/improvedFind/improvedFind.go
[maxwell@MaxwellDBA improvedFind]$ cat improvedFind.go
package main

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

func main() {

   minusS := flag.Bool("s",false,"Sockets")
   minusP := flag.Bool("p",false, "Pipes")
   minusSL := flag.Bool("sl",false,"Symbolic Links")
   minusD := flag.Bool("d", false,"Directories")
   minusF := flag.Bool("f", false, "Files")

   flag.Parse()
   flags := flag.Args()

   printAll := false
   if *minusS && *minusP && *minusSL && *minusD && *minusF {
         printAll = true
   }

   if !(*minusS || *minusP || *minusSL || *minusD || *minusF){
        printAll = true
   }

   if len(flags) == 0 {
         fmt.Println("Not enough arguments!")
         os.Exit(1)
   }

   Path := flags[0]

   walkFunction := func(path string, info os.FileInfo, err error) error {
           fileInfo, err := os.Stat(path)
           if err != nil {
                return err
           }

           if printAll {
                 fmt.Println(path)
                 return nil
           }

           mode := fileInfo.Mode()
           if mode.IsRegular() && *minusF {
                 fmt.Println(path)
                 return nil
           }

           if mode.IsDir() && *minusD {
                 fmt.Println(path)
                 return nil
           }

           fileInfo, _ = os.Lstat(path)
           if fileInfo.Mode()&os.ModeSymlink != 0 {
                 if *minusSL {
                       fmt.Println(path)
                       return nil
                }
           }

           if fileInfo.Mode()&os.ModeNamedPipe != 0 {
                 if *minusP {
                      fmt.Println(path)
                      return nil
                }
          }

          if fileInfo.Mode()&os.ModeSocket != 0 {
                if *minusS {
                      fmt.Println(path)
                      return nil
                }
          }

          return nil
   }

   err := filepath.Walk(Path, walkFunction)
   if err != nil {
         fmt.Println(err)
         os.Exit(1)
   }

 }
[maxwell@MaxwellDBA improvedFind]$ 

Excluding a file extension from the find output

A file extension is the part of a filename after the last dot(.) character.

[maxwell@MaxwellDBA improvedFind]$ pwd
/home/maxwell/goproject/improvedFind
[maxwell@MaxwellDBA improvedFind]$ go run finalFind.go -ext=py ~/goproject/improvedFind/
/home/maxwell/goproject/improvedFind/
/home/maxwell/goproject/improvedFind/aLink
/home/maxwell/goproject/improvedFind/excludeFind.go
/home/maxwell/goproject/improvedFind/finalFind.go
/home/maxwell/goproject/improvedFind/improvedFind.go
[maxwell@MaxwellDBA improvedFind]$ go run finalFind.go ~/goproject/improvedFind/        
/home/maxwell/goproject/improvedFind/
/home/maxwell/goproject/improvedFind/aLink
/home/maxwell/goproject/improvedFind/dT.py
/home/maxwell/goproject/improvedFind/excludeFind.go
/home/maxwell/goproject/improvedFind/finalFind.go
/home/maxwell/goproject/improvedFind/improvedFind.go
[maxwell@MaxwellDBA improvedFind]$ cat finalFind.go
package main

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

func excludeNames(name string, exclude string) bool {
   if exclude == "" {
         return false
   }
   if filepath.Base(name) == exclude {
         return true
   }
   return false
}

func excludeExtensions(name string, extension string) bool{
     if extension == "" {
          return false
     }
     basename := filepath.Base(name)
     s := strings.Split(basename, ".")
     length := len(s)
     basenameExtension := s[length-1]
     if basenameExtension == extension {
           return true
     }
     return false
}
func main() {

   minusS := flag.Bool("s",false,"Sockets")
   minusP := flag.Bool("p",false, "Pipes")
   minusSL := flag.Bool("sl",false,"Symbolic Links")
   minusD := flag.Bool("d", false,"Directories")
   minusF := flag.Bool("f", false, "Files")
   minusX := flag.String("x","", "Files")
   minusEXT := flag.String("ext", "", "Extensions")

   flag.Parse()
   flags := flag.Args()

   printAll := false
   if *minusS && *minusP && *minusSL && *minusD && *minusF {
         printAll = true
   }

   if !(*minusS || *minusP || *minusSL || *minusD || *minusF){
        printAll = true
   }

   if len(flags) == 0 {
         fmt.Println("Not enough arguments!")
         os.Exit(1)
   }

   Path := flags[0]

   walkFunction := func(path string, info os.FileInfo, err error) error {
           fileInfo, err := os.Stat(path)
           if err != nil {
                 return err
           }

           if excludeNames(path, *minusX){
                 return nil
           }
           if excludeExtensions(path, *minusEXT){
                 return nil
           }
           if printAll {
                 fmt.Println(path)
                 return nil
           }

           mode := fileInfo.Mode()
           if mode.IsRegular() && *minusF {
                 fmt.Println(path)
                 return nil
           }

           if mode.IsDir() && *minusD {
                 fmt.Println(path)
                 return nil
           }

           fileInfo, _ = os.Lstat(path)
           if fileInfo.Mode()&os.ModeSymlink != 0 {
                 if *minusSL {
                       fmt.Println(path)
                       return nil
                 }
           }

           if fileInfo.Mode()&os.ModeNamedPipe != 0 {
                 if *minusP {
                      fmt.Println(path)
                      return nil
                 }
          }

          if fileInfo.Mode()&os.ModeSocket != 0 {
                if *minusS {
                      fmt.Println(path)
                      return nil
                }
          }

          return nil
   }

   err := filepath.Walk(Path, walkFunction)
   if err != nil {
         fmt.Println(err)
         os.Exit(1)
   }

 }
[maxwell@MaxwellDBA improvedFind]$ 

Using regular expressions

how to add support for regular expression in finalFind.go: the name of the last version of the tool will be regExpFind.go . The new flag will be called -re and it will be included in the output unless it is excluded by another command-line option.

[maxwell@MaxwellDBA improvedFind]$ go run regExpFind.go -re=anotherPackage /home/maxwell/goproject/
/home/maxwell/goproject/improvedFind/anotherPackage
/home/maxwell/goproject/improvedFind/anotherPackage/anotherPackage.go
[maxwell@MaxwellDBA improvedFind]$ go run regExpFind.go -ext=go -re=anotherPackage /home/maxwell/goproject/
/home/maxwell/goproject/improvedFind/anotherPackage
[maxwell@MaxwellDBA improvedFind]$ go run regExpFind.go /home/maxwell/goproject/ | grep anotherPackage/    
/home/maxwell/goproject/improvedFind/anotherPackage/anotherPackage.go
[maxwell@MaxwellDBA improvedFind]$ cat regExpFind.go
package main

import (
   "flag"
   "fmt"
   "os"
   "path/filepath"
   "strings"
   "regexp"
)

func excludeNames(name string, exclude string) bool {
   if exclude == "" {
         return false
   }
   if filepath.Base(name) == exclude {
         return true
   }
   return false
}

func excludeExtensions(name string, extension string) bool{
     if extension == "" {
          return false
     }
     basename := filepath.Base(name)
     s := strings.Split(basename, ".")
     length := len(s)
     basenameExtension := s[length-1]
     if basenameExtension == extension {
           return true
     }
     return false
}

func regularExpression(path, regExp string) bool {
    if regExp == "" {
          return true
     }
     r, _ := regexp.Compile(regExp)
     matched := r.MatchString(path)
     return matched
}

func main() {

   minusS := flag.Bool("s",false,"Sockets")
   minusP := flag.Bool("p",false, "Pipes")
   minusSL := flag.Bool("sl",false,"Symbolic Links")
   minusD := flag.Bool("d", false,"Directories")
   minusF := flag.Bool("f", false, "Files")
   minusX := flag.String("x","", "Files")
   minusEXT := flag.String("ext", "", "Extensions")
   minusRE := flag.String("re", "","Regular Expression")

   flag.Parse()
   flags := flag.Args()

   printAll := false
   if *minusS && *minusP && *minusSL && *minusD && *minusF {
         printAll = true
   }

   if !(*minusS || *minusP || *minusSL || *minusD || *minusF){
        printAll = true
   }

   if len(flags) == 0 {
         fmt.Println("Not enough arguments!")
         os.Exit(1)
   }

   Path := flags[0]

   walkFunction := func(path string, info os.FileInfo, err error) error {
           fileInfo, err := os.Stat(path)
           if err != nil {
                 return err
           }
           if regularExpression(path, *minusRE) == false {
                 return nil
           }
           if excludeNames(path, *minusX){
                 return nil
           }
           if excludeExtensions(path, *minusEXT){
                 return nil
           }
           if printAll {
                 fmt.Println(path)
                 return nil
           }

           mode := fileInfo.Mode()
           if mode.IsRegular() && *minusF {
                 fmt.Println(path)
                 return nil
           }

           if mode.IsDir() && *minusD {
                 fmt.Println(path)
                 return nil
           }

           fileInfo, _ = os.Lstat(path)
           if fileInfo.Mode()&os.ModeSymlink != 0 {
                 if *minusSL {
                       fmt.Println(path)
                       return nil
                 }
           }

           if fileInfo.Mode()&os.ModeNamedPipe != 0 {
                 if *minusP {
                      fmt.Println(path)
                      return nil
                 }
          }

          if fileInfo.Mode()&os.ModeSocket != 0 {
                if *minusS {
                      fmt.Println(path)
                      return nil
                }
          }

          return nil
   }

   err := filepath.Walk(Path, walkFunction)
   if err != nil {
         fmt.Println(err)
         os.Exit(1)
   }

 }
[maxwell@MaxwellDBA improvedFind]$ 

Creating a copy of a directory structure

Go program that creates a copy of a directory structure in another directory.

This means that any files in the input directory will not be copied to the destination directory,only the directories will be copied.

[root@MaxwellDBA ~]# ln -s /user/local/bin /home/maxwell/goproject/cpStructure/aLink

[root@MaxwellDBA cpStructure]# su - maxwell
Last login: Thu Dec 15 14:38:20 CST 2022 on pts/0
[maxwell@MaxwellDBA ~]$ cd /home/maxwell/goproject/cpStructure
[maxwell@MaxwellDBA cpStructure]$ ls -ltr
total 4
-rw-rw-r-- 1 maxwell maxwell 1443 Dec 15 16:54 cpStructure.go
lrwxrwxrwx 1 root    root      15 Dec 15 17:01 aLink -> /user/local/bin
[maxwell@MaxwellDBA cpStructure]$
[maxwell@MaxwellDBA cpStructure]$ go run cpStructure.go ~/goproject/cpStructure /tmp/newCode
Skipping /home/maxwell/goproject/cpStructure/aLink
[maxwell@MaxwellDBA cpStructure]$ ls -l /home/maxwell/goproject/cpStructure/aLink
lrwxrwxrwx 1 root root 15 Dec 15 17:01 /home/maxwell/goproject/cpStructure/aLink -> /user/local/bin
[maxwell@MaxwellDBA cpStructure]$ 
[maxwell@MaxwellDBA cpStructure]$ 
[maxwell@MaxwellDBA cpStructure]$ cat cpStructure.go
package main

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

func main() {
   minusTEST := flag.Bool("test", false, "Test run!")

   flag.Parse()
   flags := flag.Args()

   if len(flags) == 0 || len(flags) == 1 {
        fmt.Println("Not enough arguments!")
        os.Exit(1)
   }

   Path := flags[0]
   NewPath := flags[1]


   permissions := os.ModePerm
   _, err := os.Stat(NewPath)
   if os.IsNotExist(err) {
         os.MkdirAll(NewPath, permissions)
   } else {
        fmt.Println(NewPath, "already exists - quitting...")
        os.Exit(1)
  }


 walkFunction := func(currentPath string, info os.FileInfo, err error) error {
         fileInfo, _ := os.Lstat(currentPath)
         if fileInfo.Mode()&os.ModeSymlink != 0 {
                fmt.Println("Skipping", currentPath)
                return nil
         }

         fileInfo, err = os.Stat(currentPath)
         if err != nil {
                fmt.Println("*", err)
                return err
        }

        mode := fileInfo.Mode()
        if mode.IsDir() {
             tempPath := strings.Replace(currentPath, Path, "", 1)
             pathToCreate := NewPath + "/" + filepath.Base(Path) + tempPath

             if *minusTEST {
                   fmt.Println(":", pathToCreate)
                   return nil
             }

             _, err := os.Stat(pathToCreate)
             if os.IsNotExist(err) {
                   os.MkdirAll(pathToCreate, permissions)
             } else {
                    fmt.Println("Did not create", pathToCreate, ":", err)
             }
        }
        return nil
 }
 err= filepath.Walk(Path, walkFunction)
 if err != nil {
       fmt.Println(err)
       os.Exit(1)
 }
}
[maxwell@MaxwellDBA cpStructure]$ 
### 回答1: 你可以使用下面的Python代码来移动文件到新的目录:import os source = '//old/directory/' destination = '//new/directory/' files = os.listdir(source) for f in files: sourcefile = os.path.join(source, f) destinationfile = os.path.join(destination, f) os.rename(sourcefile, destinationfile) ### 回答2: 可以使用Python的os模块来实现将文件移动到新目录的功能。下面是一个示例代码: ```python import os import shutil def move_files(source_dir, destination_dir): # 检查源目录和目标目录是否存在 if not os.path.exists(source_dir): print("源目录不存在!") return if not os.path.exists(destination_dir): print("目标目录不存在!") return # 获取源目录下的所有文件 files = os.listdir(source_dir) # 循环遍历每个文件并将其移动到目标目录 for file_name in files: # 构建源文件和目标文件的路径 source_file = os.path.join(source_dir, file_name) destination_file = os.path.join(destination_dir, file_name) # 使用shutil库的move函数将文件移动到目标目录 shutil.move(source_file, destination_file) print("文件移动完成!") # 示例用法 source_directory = "源目录路径" destination_directory = "目标目录路径" move_files(source_directory, destination_directory) ``` 以上代码将会把源目录下的所有文件移动到目标目录中。请将"源目录路径"和"目标目录路径"替换为实际的目录路径。注意,如果目标目录已经存在同名文件,则会覆盖该文件。 ### 回答3: 下面是一个使用Python将文件移动到新目录的示例: ```python import os import shutil def move_files(source_dir, dest_dir): # 检查源目录是否存在 if not os.path.exists(source_dir): print("源目录不存在!") return # 检查目标目录是否存在,如果不存在则创建它 if not os.path.exists(dest_dir): os.makedirs(dest_dir) # 遍历源目录中的所有文件 for file_name in os.listdir(source_dir): source_file = os.path.join(source_dir, file_name) dest_file = os.path.join(dest_dir, file_name) # 如果源文件是一个文件而不是目录,则将其移动到目标目录中 if os.path.isfile(source_file): shutil.move(source_file, dest_file) print("文件移动完成!") # 使用示例 source_directory = "/path/to/source_directory" destination_directory = "/path/to/destination_directory" move_files(source_directory, destination_directory) ``` 以上代码首先检查源目录是否存在,如果不存在则输出错误信息并停止执行。然后检查目标目录是否存在,如果不存在则创建它。 接下来,它遍历源目录中的所有文件,并将每个文件移动到目标目录中。 最后,输出完成消息。 你需要将`/path/to/source_directory`和`/path/to/destination_directory`替换为你的实际路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值