How can I stop printing Terminal in Swift

I want make this below code works for Swift, the codes works okay without /dev/null 2>&1, as soon as I add /dev/null 2>&1, it does not work, how can I add it correctly?

let task = Process()
task.executableURL = URL(fileURLWithPath: "/bin/bash/dev/null 2>&1")
task.arguments = ["-c", """
                    echo "Hello, world!"
                    cd ${HOME}
                    cd Desktop
                    mkdir "New Folder"
                    echo "Folder is Successfully created!"
                    """]
task.launch()

Two main issues here:

  1. The executable URL to the binary you'd like to run needs to point to the binary — it can't take arguments, because /bin/bash/dev/null 2>&1 is not a valid path on disk. If you want to run /bin/bash, the executable URL can only contain /bin/bash
  2. The redirection you're trying to perform isn't written out quite correctly either. Briefly:
    • 2>&1 in bash means "please point stderr (2) to where stdout (1) is currently pointing"
    • In order to redirect stdout first, it's not enough to just specify /dev/null — you need to tell bash "please point stdout to /dev/null", which is done with the shorthand >/dev/null (note the leading > meaning "redirection")

The syntax for these redirections is part of the actual shell you're running, and although bash might understand >/dev/null, this won't work for all processes.

One way you can request this redirection of bash is to include the redirection request inside of the shell script you're running (i.e., what you pass in to -c). This starts getting into the specifics of bash and how it handles redirections, but an example of how to achieve this:

task.arguments = ["-c", """
                        exec >/dev/null 2>&1
                        # The rest of your script.
                        """]

That exec line causes bash to effect the redirection, and it remains active for the rest of the script. Explaining the specifics might be out of scope, but check out How to redirect output of an entire shell script within the script itself? for more information.

However:

Instead of this bash-specific approach, a less fragile and more expressive way to achieve exactly this is to explicitly set the .standardOutput and .standardError properties on the Process itself. You can redirect stdout and stderr from outside of bash altogether with the following:

let task = Process()
task.executableURL = URL(fileURLWithPath: "/bin/bash")
task.arguments = ["-c", "..."]
task.standardOutput = FileHandle.nullDevice // Equivalent to /dev/null
task.standardError = FileHandle.nullDevice
task.launch()

.standardInput, .standardOutput, and .standardError on a Process help direct where the process's input comes from, and where its output goes. By default, those are inherited from your current process (which is why you're even seeing bash's output in your own output to begin with), but you can assign a FileHandle to write the output to a file, or set a Pipe to be able to read the output directly.

The above redirection will work for any process, not just bash, and it's recommended you use these semantic properties over relying on bash parsing.


If you don't care about redirecting to /dev/null specifically, you can alternatively close the process's stdout and stderr by passing in nil instead of FileHandle.nullDevice:

task.standardOutput = nil
task.standardError = nil

For this specific application, this assignment will have the same effect as redirecting to /dev/null: output from your script will be silenced.

There is technically a difference between these (if the script were inspecting where its stdout and stderr were being output to), but in the most common use cases, this would be equivalent. Consider using this as a "simplification" over referring to FileHandle.nullDevice directly.