Starting a new project

  • go mod init github.com/fractal-bootcamp/malin-scripting

types and variables

  • basic variable declaration
	var age int
  • multiple variable declaration
	var x, y int
  • variable declaration with initial value
	var message string = "Hello"
  • Multiple variable declaration with different types:
	var (
    name1 type1
    name2 type2
)
  • short variable declaration with type inferred
name := value
  • declare custom types
    • type TypeName BaseType (e.g.
type Celsius float64
  • Declaring struct types: Struct types are composite types that group together zero or more fields of different types under a single name.
type Person struct { 
	Name string 
	Age int 
}
  • Pointer types: Pointer types hold the memory address of a value instead of the value itself.
    • A pointer is a variable that stores the memory address of another variable.
    • It doesn’t store the value itself, but rather “points” to where the value is stored in the computer’s memory.
var ptr *int
x := 10
xPtr := &x // creates a pointer to the memory address fo 'x'
//(xPtr now implicitly has a type of *int, i.e. pointer to integer)
 
x = 10 
xPtr = 0xc0000b4008 (this address may vary) 
*xPtr = 10 
*xPtr = 20
//After change, changes the value at the address stored in `xPtr`
x = 20
 
 

Why would you use a pointer?

  • When you pass a variable to a function in Go, it’s passed by value (a copy is made). Pointers allow you to modify the original variable.
  • Passing pointers is more efficient for large structures because you’re just passing an address, not copying the entire structure.
  • pointers become very useful in scenarios like function calls where you need to modify the original variable, not just a local copy.

os.stdout

When you see something like this

cmd.Stdout = os.Stdout

it means “I want you to show me on the terminal output, i.e. my systems standard output, whatever the program prints to its standard output”

  • cmd.Stdout represents where the command (the external program we’re running) will send its standard output.
  • os.Stdout represents the standard output of our Go program, which is typically the terminal or console where the program is running.
  • By assigning os.Stdout to cmd.Stdout, we’re saying: “Take whatever the command would normally print to its own stdout, and instead, print it to our program’s stdout (the terminal).”

mkdir

You can use the GO os. package to perform common folder/os operations. For example to make a new directory:

// os.Mkdir(directoryName, chmod)
os.Mkdir("dirname", 0700)
 
// Unix Permissions Primer
Every file has an `user`. This is a user on the system. Every file also has a `group`. This is a group on the system. A `user` can be in one or more `group`s. A file has exactly one `user` and one `group` that "own" the file.
 
The next three numbers indicate the three permissions: one for the `user``group`, and `other` (everybody that is not `user` or `group`), in that order.
 
 
// Permission Bits Primer
 
Permission bits are historically given in Octal, so the literal value must be prefixed by a `0`. Otherwise it will be interpreted as decimal and give confusing results. This is consistent with the Linux command `chmod`.
 
`read` and `write` should be self-explanatory. `execute` means that you can run a file with `./ls`
 
+-----+---+--------------------------+
| rwx | 7 | Read, write and execute  |
| rw- | 6 | Read, write              |
| r-x | 5 | Read, and execute        |
| r-- | 4 | Read,                    |
| -wx | 3 | Write and execute        |
| -w- | 2 | Write                    |
| --x | 1 | Execute                  |
| --- | 0 | no permissions           |
+------------------------------------+
 
+------------+------+-------+
| Permission | Octal| Field |
+------------+------+-------+
| rwx------  | 0700 | User  |
| ---rwx---  | 0070 | Group |
| ------rwx  | 0007 | Other |
+------------+------+-------+
 
 

running terminal commands in Go scripts

Below are some patterns that you can use for doing terminal commands

// this function allows you to interact with the user in the terminal
func runInteractiveCommand(name string, arg ...string) error {
 
cmd := exec.Command(name, arg...)
 
cmd.Stdout = os.Stdout
 
cmd.Stderr = os.Stderr
 
cmd.Stdin = os.Stdin
 
return cmd.Run()
}
 
// read from the users input
reader := bufio.NewReader(os.Stdin)
 
fmt.Print("Okay let's setup the frontend. What do you want to name this folder? ")
 
projectName, _ := reader.ReadString('\n')
 
projectName = strings.TrimSpace(projectName)
 
 
// define the command you want to execute on the terminal
 
var cmd *exec.Cmd
 
cmd = exec.Command("npm", "create", "vite@latest", projectName)
 
 
// run the command
err := runInteractiveCommand(cmd.Path, cmd.Args[1:]...)
 
if err != nil {
 
fmt.Printf("Error: ", err)
 
os.Exit(1)
 
}