Skip to content

Commit

Permalink
updated
Browse files Browse the repository at this point in the history
  • Loading branch information
AspieSoft committed Nov 20, 2023
1 parent 5824f3e commit 776c8b8
Show file tree
Hide file tree
Showing 3 changed files with 232 additions and 63 deletions.
287 changes: 229 additions & 58 deletions bash/bash.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,148 @@ import (
"os/exec"
)

// Run will run a bash command based on the given args
//
// note: stdin is piped to the os logs
//
// @dir: a directory to run the command in (set to an empty string to disable)
//
// @env: an optional list of environment variables (set to nil to disable)
//
// @liveOutput[0]: set to true to pipe stdout and stderr to the os
//
// @liveOutput[1]: set to false if you only want to pipe stdout to the os, and keep stderr hidden
/*
Run will run a bash command based on the given args
note: stdin is piped to the os logs
@dir: a directory to run the command in (set to an empty string to disable)
@env: an optional list of environment variables (set to nil to disable)
[optional]
@liveOutput[0]: set to true to pipe stdout and stderr to the os
@liveOutput[1]: set to false to only pipe stdout to the os, and keep stderr hidden
*/
func Run(args []string, dir string, env []string, liveOutput ...bool) (output []byte, err error) {
arg1 := args[0]
args = args[1:]
cmd := exec.Command(arg1, args...)
if dir != "" {
cmd.Dir = dir
}
if cmd.Env == nil {
cmd.Env = os.Environ()
}
if env != nil {
if cmd.Env == nil {
cmd.Env = []string{}
cmd.Env = append(cmd.Env, env...)
}
cmd.Stdin = os.Stdin
if len(liveOutput) != 0 && liveOutput[0] == true {
cmd.Stdout = os.Stdout
if len(liveOutput) <= 1 || liveOutput[1] == true {
cmd.Stderr = os.Stderr
}
return []byte{}, cmd.Run()
}
return cmd.CombinedOutput()
}

/*
RunRaw will run an unescaped (unquoted) bash command as a different user
this method uses `bash -c` to get around the auto quotes added by golang
note: user input is Not recommended for this method
note: stdin is piped to the os logs
@cmdStr: the command to run
@dir: a directory to run the command in (set to an empty string to disable)
@env: an optional list of environment variables (set to nil to disable)
[optional]
@liveOutput[0]: set to true to pipe stdout and stderr to the os
@liveOutput[1]: set to false to only pipe stdout to the os, and keep stderr hidden
*/
func RunRaw(cmdStr string, dir string, env []string, liveOutput ...bool) (output []byte, err error) {
cmd := exec.Command(`bash`, `-c`, cmdStr)
if dir != "" {
cmd.Dir = dir
}
if cmd.Env == nil {
cmd.Env = os.Environ()
}
if env != nil {
cmd.Env = append(cmd.Env, env...)
}
cmd.Stdin = os.Stdin
if len(liveOutput) != 0 && liveOutput[0] == true {
cmd.Stdout = os.Stdout
if len(liveOutput) <= 1 || liveOutput[1] == true {
cmd.Stderr = os.Stderr
}
return []byte{}, cmd.Run()
}
return cmd.CombinedOutput()
}

/*
RunUser will run an unescaped (unquoted) bash command as a specified user
this method uses `runuser -l [user] -c`
note: user input is Not recommended for this method
note: stdin is piped to the os logs
@cmdStr: the command to run
@user: the username to run the command as
@dir: a directory to run the command in (set to an empty string to disable)
@env: an optional list of environment variables (set to nil to disable)
[optional]
@liveOutput[0]: set to true to pipe stdout and stderr to the os
@liveOutput[1]: set to false to only pipe stdout to the os, and keep stderr hidden
*/
func RunUser(cmdStr string, user string, dir string, env []string, liveOutput ...bool) (output []byte, err error) {
cmd := exec.Command(`runuser`, `-l`, user, `-c`, cmdStr)
if dir != "" {
cmd.Dir = dir
}
if cmd.Env == nil {
cmd.Env = os.Environ()
}
if env != nil {
cmd.Env = append(cmd.Env, env...)
}
cmd.Stdin = os.Stdin
if len(liveOutput) != 0 && liveOutput[0] == true {
cmd.Stdout = os.Stdout
if len(liveOutput) <= 1 || liveOutput[1] == true {
cmd.Stderr = os.Stderr
}
return []byte{}, cmd.Run()
}
return cmd.CombinedOutput()
}

/*
RunUserFile will run a bash file as a specified user
this method uses `pkexec --user [user]` to simulate a user in a normal desktop environment
note: user input is Not recommended for this method
note: stdin is piped to the os logs
@file: the file to run
@user: the username to run the command as
@dir: a directory to run the command in (set to an empty string to disable)
@env: an optional list of environment variables (set to nil to disable)
[optional]
@liveOutput[0]: set to true to pipe stdout and stderr to the os
@liveOutput[1]: set to false to only pipe stdout to the os, and keep stderr hidden
*/
func RunUserFile(file string, args []string, user string, dir string, env []string, liveOutput ...bool) (output []byte, err error) {
cmd := exec.Command(`pkexec`, append([]string{`--user`, user, file}, args...)...)
if dir != "" {
cmd.Dir = dir
}
if cmd.Env == nil {
cmd.Env = os.Environ()
}
if env != nil {
cmd.Env = append(cmd.Env, env...)
}
cmd.Stdin = os.Stdin
Expand All @@ -41,14 +161,17 @@ func Run(args []string, dir string, env []string, liveOutput ...bool) (output []
return cmd.CombinedOutput()
}

// Pipe allows you to pipe multiple bash commands
//
// example (bash):
// echo "test" | tee -a "./test.txt"
// example (go):
// Pipe(".", []string{"echo", "test"}, []string{"tee", "-a", "./test.txt"})
//
// @dir: a directory to run the command in (set to an empty string to disable)
/*
Pipe allows you to pipe multiple bash commands
[example (bash)]
echo "test" | tee -a "./test.txt"
[example (go)]
bash.Pipe(".", []string{"echo", "test"}, []string{"tee", "-a", "./test.txt"})
@dir: a directory to run the command in (set to an empty string to disable)
*/
func Pipe(dir string, args ...[]string){
if len(args) == 1 {
arg1 := args[0][0]
Expand All @@ -67,6 +190,10 @@ func Pipe(dir string, args ...[]string){
cmd[0].Dir = dir
}

if cmd[0].Env == nil {
cmd[0].Env = os.Environ()
}

for i := 1; i < len(args); i++ {
arg0 = args[i][0]
args0 = args[i][1:]
Expand All @@ -79,6 +206,10 @@ func Pipe(dir string, args ...[]string){
cmd[i].Dir = dir
}

if cmd[i].Env == nil {
cmd[i].Env = os.Environ()
}

cmd[i-1].Start()

go func(i int){
Expand All @@ -94,14 +225,14 @@ func Pipe(dir string, args ...[]string){
cmd[len(cmd)-1].Wait()
}

// PipeMultiDir allows you to pipe multiple bash commands with a different directory for each of them
//
// note: the first arg is the directory
//
// example (bash):
// cat "/dir1/test.txt" | tee -a "./dir2/test.txt"
// example (go):
// Pipe(".", []string{"/dir1", "cat", "test.txt"}, []string{"./dir2", "tee", "-a", "./test.txt"})
/*
PipeMultiDir allows you to pipe multiple bash commands with a different directory for each of them
note: the first arg is the directory
[example]
bash.PipeMultiDir([]string{"/dir1", "cat", "test.txt"}, []string{"./dir2", "tee", "-a", "./test.txt"})
*/
func PipeMultiDir(args ...[]string){
if len(args) == 1 {
arg1 := args[0][0]
Expand All @@ -121,6 +252,10 @@ func PipeMultiDir(args ...[]string){
cmd[0].Dir = dir
}

if cmd[0].Env == nil {
cmd[0].Env = os.Environ()
}

for i := 1; i < len(args); i++ {
dir = args[i][0]
arg0 = args[i][1]
Expand All @@ -134,6 +269,10 @@ func PipeMultiDir(args ...[]string){
cmd[i].Dir = dir
}

if cmd[i].Env == nil {
cmd[i].Env = os.Environ()
}

cmd[i-1].Start()

go func(i int){
Expand All @@ -149,39 +288,71 @@ func PipeMultiDir(args ...[]string){
cmd[len(cmd)-1].Wait()
}

// RunRaw will run an unescaped (unquoted) bash command
//
// this used `bash -c` to get around the auto quotes added by golang
//
// note: user input is Not recommended for this method
//
// note: stdin is piped to the os logs
//
// @dir: a directory to run the command in (set to an empty string to disable)
//
// @env: an optional list of environment variables (set to nil to disable)
//
// @liveOutput[0]: set to true to pipe stdout and stderr to the os
//
// @liveOutput[1]: set to false if you only want to pipe stdout to the os, and keep stderr hidden
func RunRaw(cmdStr string, dir string, env []string, liveOutput ...bool) (output []byte, err error) {
cmd := exec.Command(`bash`, `-c`, cmdStr)
/*
PipeMultiDirEnv is just like the 'PipeMultiDir' method, but it also allows you to add custom envirronment vars
note: the first arg is the directory
[example]
bash.PipeMultiDirEnv([]string{`MyEnvVar=CustomValue`}, []string{"/dir1", "cat", "test.txt"}, []string{"./dir2", "tee", "-a", "./test.txt"})
*/
func PipeMultiDirEnv(env []string, args ...[]string){
if len(args) == 1 {
arg1 := args[0][0]
args1 := args[0][1:]
c1 := exec.Command(arg1, args1...)
c1.Stdout = os.Stdout
}

cmd := []*exec.Cmd{}

dir := args[0][0]
arg0 := args[0][1]
args0 := args[0][2:]
cmd = append(cmd, exec.Command(arg0, args0...))
cmd[0].Stdin = os.Stdin
if dir != "" {
cmd.Dir = dir
cmd[0].Dir = dir
}

if cmd[0].Env == nil {
cmd[0].Env = os.Environ()
}
if env != nil {
if cmd.Env == nil {
cmd.Env = []string{}
}
cmd.Env = append(cmd.Env, env...)
cmd[0].Env = append(cmd[0].Env, env...)
}
cmd.Stdin = os.Stdin
if len(liveOutput) != 0 && liveOutput[0] == true {
cmd.Stdout = os.Stdout
if len(liveOutput) <= 1 || liveOutput[1] == true {
cmd.Stderr = os.Stderr

for i := 1; i < len(args); i++ {
dir = args[i][0]
arg0 = args[i][1]
args0 = args[i][2:]
cmd = append(cmd, exec.Command(arg0, args0...))

pr, pw := io.Pipe()
cmd[i-1].Stdout = pw
cmd[i].Stdin = pr
if dir != "" {
cmd[i].Dir = dir
}
return []byte{}, cmd.Run()

if cmd[i].Env == nil {
cmd[i].Env = os.Environ()
}
if env != nil {
cmd[i].Env = append(cmd[i].Env, env...)
}

cmd[i-1].Start()

go func(i int){
defer pw.Close()

cmd[i-1].Wait()
}(i)
}
return cmd.CombinedOutput()

cmd[len(cmd)-1].Stdout = os.Stdout

cmd[len(cmd)-1].Start()
cmd[len(cmd)-1].Wait()
}
2 changes: 1 addition & 1 deletion cache/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ module github.com/AspieSoft/goutil/cache

go 1.20

require github.com/AspieSoft/goutil/v7 v7.5.0
require github.com/AspieSoft/goutil/v7 v7.5.1

require github.com/AspieSoft/go-regex-re2/v2 v2.2.0 // indirect
6 changes: 2 additions & 4 deletions cache/go.sum
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
github.com/AspieSoft/go-regex-re2/v2 v2.2.0 h1:CK9+SYs7BYy+lV/JrmRbyF+SuTF+e+BIyjKGjKJQzLg=
github.com/AspieSoft/go-regex-re2/v2 v2.2.0/go.mod h1:w+vA1zICvB4OQZGY8KdpyMwjwbFXdnZt9iQ7jRR+ycQ=
github.com/AspieSoft/goutil/v7 v7.4.7 h1:g6nkT5LotJJnELTvkamDR5qObanBv0saw1cK7wGSdCY=
github.com/AspieSoft/goutil/v7 v7.4.7/go.mod h1:JGAt912jBwFrTXiazla1FTVqSI3zDetUKR5HJb9ND5I=
github.com/AspieSoft/goutil/v7 v7.5.0 h1:4fUMgKQgprTuYprZxbHbYMV7y2JASVOX8G/gBOunAFU=
github.com/AspieSoft/goutil/v7 v7.5.0/go.mod h1:JGAt912jBwFrTXiazla1FTVqSI3zDetUKR5HJb9ND5I=
github.com/AspieSoft/goutil/v7 v7.5.1 h1:N2ZoRBjQ2pmQkHzs0rnFV7LSr22Mv30WNDHJ9o9pZA8=
github.com/AspieSoft/goutil/v7 v7.5.1/go.mod h1:JGAt912jBwFrTXiazla1FTVqSI3zDetUKR5HJb9ND5I=

0 comments on commit 776c8b8

Please sign in to comment.