John Armstrong John Armstrong - 29 days ago 18
Swift Question

Task() is escaping quotes

Working with Process() to create a network monitoring task.

I am trying to send a single quoted argument to Task (the process name to monitor). This needs to be single quoted since it can have spaces in it. (see task.arguments?.append("-p '(procName!)'") below )

task = Process()
pipe = Pipe()
task.launchPath = "/usr/bin/nettop"

task.arguments = ["-j time,interface,state,bytes_in,bytes_out","-k rx_dupe,rx_ooo,re-tx,rtt_avg,rcvsize,tx_win,tc_class,tc_mgt,cc_algo,P,C,R,W","-n","-L 0"]
var procName = currentSelection?.procname
if(procName != nil && procName != "") {
task.arguments?.append("-p '\(procName!)'")
}
task.standardOutput = pipe
task.launch()


According to docs no quoting is required since no shell expansion occurs

https://developer.apple.com/reference/foundation/process/1408983-arguments

Specifically

The NSTask object converts both path and the strings in arguments to appropriate C-style strings (using fileSystemRepresentation) before passing them to the task via argv[] . The strings in arguments do not undergo shell expansion, so you do not need to do special quoting, and shell variables, such as $PWD, are not resolved.

However, it seems to be automagically escaping them and sending that escaped version to the OS as a literal. The debugger shows them as escaped, whether or not I manually escape them so there is some awareness of their state here. I can't get a full command line for nettop to show in top, htop or ps -f but circumstantially, when I added the procName to the task argument list the command gets no data back other then the normal nettop headers. This shows that nettop is running, its just not finding its process to sniff.

So, the question is: How can I send a single quoted argument (like 'Google Chrome') to a Process() as an argument?

Answer

The process name must be passed as a single argument without any quoting:

var procName = currentSelection?.procname
if (procName != nil && procName != "") {
    task.arguments! += ["-p", procName! ]
}

or perhaps better

if let procName = currentSelection?.procname, !procName.isEmpty {
    task.arguments! += ["-p", procName ]
}
Comments