package main
import("fmt""runtime")funcmain(){// The runtime.GOOS constant can be used to detect the OS at runtime,// since this constant is only set at runtime. os := runtime.GOOS
switch os {case"windows": fmt.Println("Windows")case"darwin": fmt.Println("MacOS")case"linux": fmt.Println("Linux")default: fmt.Printf("%s.\n", os)}// The runtime.GOARCH constant can be used to determine the target architecture of a running program. fmt.Println(runtime.GOARCH)}// Output:// Linux// amd64
GOOS constant to determine the operating system your Go program is running on. Here's an example of how to check the operating system in Go.
package main
import("fmt""os""path/filepath")funccheckErr(err error){if err !=nil{panic(err)}}funcmain(){// The simplest way to create a temporary file is to call os.CreateTemp.// It will create and open the file for reading and writing.// We used "" as the first argument, so os.CreateTemp will create a file in the default directory. tmpFile, err := os.CreateTemp("","tmpfile")checkErr(err)defer os.Remove(tmpFile.Name()) fmt.Println("Temp file name:", tmpFile.Name())// Write some data to the temporary file_, err = tmpFile.Write([]byte{1,2,3,4,5})checkErr(err)// If we intend to write a lot of temporary files, we may prefer to create a temporary directory.// The arguments to os.MkdirTemp are the same as for os.CreateTemp, but it returns the directory name rather than the opened file. dName, err := os.MkdirTemp("","tmpdir")checkErr(err)defer os.RemoveAll(dName) fmt.Println("Temp directory name:", dName) fName := filepath.Join(dName,"testFile") err = os.WriteFile(fName,[]byte{1,2,3,4,5},0666)checkErr(err)defer os.Remove(fName)}// Output:// Temp file name: /tmp/tmpfile3400905374// Temp directory name: /tmp/tmpdir2812568099
During program execution, we often want to create data that is not needed after the program exits. Temporary files and directories are useful for this purpose because they do not pollute the file system over time.
# File management using context managerclassFileManager():def__init__(self, filename, mode): self.filename = filename
self.mode = mode
self.file=None# The __enter__ method opens the file and returns a file objectdef__enter__(self):print('Open file: {}'.format(self.filename)) self.file=open(self.filename, self.mode)return self.file# The __exit__ method takes care of closing the file on exiting the with block def__exit__(self, etype, value, traceback):print('Close file: {}'.format(self.filename)) self.file.close()# A FileManager object is created with test.txt as the filename and "write" mode# when __init__ method is executedwith FileManager('test.txt','w')as f: f.write('First line\n') f.write('Second line\n')# The file is already closed thanks to the automatic call to the __exit__ methodprint('File closed: {}\n'.format(f.closed))with FileManager('test.txt','r')as f:for line in f:print(line.rstrip())# Output#Open file: test.txt#Close file: test.txt#File closed: True##Open file: test.txt#First line#Second line#Close file: test.txt
When creating context managers using classes, be sure to ensure that the class includes methods: __enter__() and __exit__(). The __enter__() method provides a resource to be managed, and __exit__() performs cleanup operations without returning any value. To understand the basic structure of building context managers using classes, let's look at a simple FileManager class for managing files.
package main
import("bufio""fmt""os")funccheckErr(err error){if err !=nil{panic(err)}}funcmain(){ content :="Some content"// write a string (or just bytes) into a file err := os.WriteFile("/tmp/dfile1",[]byte(content),0644)checkErr(err)// open a file for writing file, err := os.Create("/tmp/dfile2")checkErr(err)// defer a Close immediately after opening a filedefer file.Close() bytesCount, err := file.Write([]byte(content))checkErr(err) fmt.Printf("wrote %d bytes\n", bytesCount) bytesCount, err = file.WriteString("Some other content\n")checkErr(err) fmt.Printf("wrote %d bytes\n", bytesCount)// flush writes to a stable storage (file system for example) file.Sync()// bufio provides buffered writers writer := bufio.NewWriter(file) bytesCount, err = writer.WriteString("Some othe buffered content\n")checkErr(err) fmt.Printf("wrote %d bytes\n", bytesCount)// ensure all buffered operations have been applied to the underlying writer writer.Flush()}
Here are examples of writing data to files using Go.
package main
import("fmt""time")funcmain(){// in this example we will choose between two channels c1 :=make(chanstring) c2 :=make(chanstring)gofunc(){ time.Sleep(1* time.Second) c1 <-"one"}()// each channel will receive a value after some timegofunc(){ time.Sleep(2* time.Second) c2 <-"two"}()// use select statement to wait for both values at the same time,// printing each one as it arrivesfor i :=0; i <2; i++{select{case msg1 :=<-c1: fmt.Println("received", msg1)case msg2 :=<-c2: fmt.Println("received", msg2)}}}
Select statement allows you to wait for multiple operations on a channel.
package main
import("fmt""time")// this is a worker that we will run in several parallel instances// these workers will receive tasks through the 'jobs' channel and send the results to 'results'// we will wait for one second for each task to simulate heavy requestsfuncworker(id int, jobs <-chanint, results chan<-int){for j :=range jobs { fmt.Println("worker", id,"started job", j) time.Sleep(time.Second) fmt.Println("worker", id,"finished job", j) results <- j *2}}funcmain(){// to use worker pool, we need to send a task and receive the execution results// therefore 2 channels are created jobs :=make(chanint,100) results :=make(chanint,100)// start 3 workers, initially blocked because no assignments yetfor w :=1; w <=3; w++{goworker(w, jobs, results)}// send 5 jobs and then close the channel, notofying that all jobs have been sentfor j :=1; j <=5; j++{ jobs <- j
}close(jobs)// collect all the results// this also ensures that the goroutines have endedfor a :=1; a <=5; a++{<-results
}}
This example shows how to implement a worker pool using channels and goroutines.
package main
import("fmt""time")// the channel is used to notify main goroutine that the function completed successfullyfuncworker(done chanbool){ fmt.Println("working...") time.Sleep(time.Second) fmt.Println("done") done <-true// send a value to indicate that the function completed successfully}funcmain(){ done :=make(chanbool,1)// create a buffered channel for notificationgoworker(done)// run worker<-done // blocked until a notification is received from the worker from the channel// if you remove the line <- done the program will close before the worker starts}
Channels can be used to synchronize execution between goroutines. Here is an example of using a channel to wait for a goroutine to complete.
#!/bin/bashdie(){echo"ERROR: $*">&2exit1}detect_os(){OS="$(uname -s)"ARCH="$(uname -m)"case"$OS"in Linux)if[ -e /etc/lsb-release ];thensource /etc/lsb-release
DIST_ID="${DISTRIB_ID}"OS_VERSION="${DISTRIB_RELEASE}"OS_CODENAME="${DISTRIB_CODENAME}"elif[ -e /etc/os-release];thensource /etc/os-release
DIST_ID="${ID}"OS_VERSION="${VERSION_ID}"OS_CODENAME="${VERSION_CODENAME}"elif[$(which lsb_release 2>/dev/null)];thenDIST_ID="$(lsb_release -s -i)"OS_VERSION="$(lsb_release -s -r)"OS_CODENAME="$(lsb_release -s -c)"else die "Colud not get OS information"ficase"$DIST_ID"in RedHat*)OS_NAME="RedHat";; debian)OS_NAME="Debian";; *)OS_NAME="${DIST_ID}";;esac;; *) die "Unsupported OS family: $OS";;esacecho"${OS}"echo"${OS_NAME}"echo"${OS_VERSION}"echo"${OS_CODENAME}"}
This script returns OS information such as type, name, codename and version. It supports the following Linux distributions: Ubuntu, Debian, CentOS, RedHat. If you want to add support for other distributions, write in the comments below.