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:
- 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
- The redirection you're trying to perform isn't written out quite correctly either. Briefly:
-
2>&1
inbash
means "please pointstderr
(2
) to wherestdout
(1
) is currently pointing" - In order to redirect
stdout
first, it's not enough to just specify/dev/null
— you need to tellbash
"please pointstdout
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.