kareman / SwiftShell

A Swift framework for shell scripting.
https://kareman.github.io/SwiftShell
MIT License
1.03k stars 87 forks source link

Wait forever when running an unzip file command #41

Closed patchthecode closed 7 years ago

patchthecode commented 7 years ago

we have this as the command.

run(bash: "unzip /User/myName/Desktop/myZipFile.zip -d /User/myName/Desktop/)

This is just supposed to unzip a rather large zip file (100Mb) But the Swift shell freezes the app.

We traced it down to where control is frozen, it is in this file Command.swift

public func finish() throws {
   self.waitUntilExit() // <-- It freezes here
   guard self.terminationStatus == 0 else {
      throw CommandError.returnedErrorCode(command: commandAsString()!, errorcode: Int(self.terminationStatus))
   }
}

We are forced to downgrade back to 3.0.0Beta in the mean time. Thanks for your work. Awesome library.

patchthecode commented 7 years ago

Ok. i tried just unzipping a small text file. Same thing. Investigating further..

patchthecode commented 7 years ago

OK. So i have now tried the runAndPrint command

and it correctly unzips the file on terminal, but, it is sad because i cannot get the output like below

let output = try SwiftShell.runAndPrint("unzip", "/Users/jt/Desktop/Bob/myZipFile.zip", "-d", "/Users/jt/Desktop/Bob")
kareman commented 7 years ago

runAndPrint doesn't return anything, so that is expected. Could you try

let output = try SwiftShell.run("unzip", "/Users/jt/Desktop/Bob/myZipFile.zip", "-d", "/Users/jt/Desktop/Bob")

to see if it is bash that never returns. If that doesn't work I'll take a look when I get back to my computer on Monday.

patchthecode commented 7 years ago

ok. I'll update this over the weekend. And give you the results.

kareman commented 7 years ago

I have tested this with runAndPrint using SwiftShell 3.0.1 and it is working fine unless unzip asks for input (if e.g. the files I am unzipping already exist in the destination) and I run it from the terminal. Then the application never finishes. If I run it in Xcode and provide the input in its console it's working fine. It doesn't matter if I build the executable with Xcode or with the Swift Package Manager.

This is very strange, I don't really have any theories at the moment. Have you found any way to work around it?

patchthecode commented 7 years ago

@kareman the workaround for now is to use runAndPrint Unfortunately, i cannot get a return value because runAndPrint was not built for that.

Although the run command it fails, note that it works with other terminal commands.. it just hangs when unzippng.

I remember way back in my school days something about flushing stdout buffers? But im not sure if this has anything to do with this. It was too long ago.

kareman commented 7 years ago

I think the problem only occurs when the “unzip” command asks for an answer to a question (like if it should overwrite already existing files). And it seems it only does this when standard input is a terminal. Some workarounds are

let output = run(bash: "null | unzip /User/myName/Desktop/myZipFile.zip -d /User/myName/Desktop/")

or

let output = "".run("unzip", "/Users/jt/Desktop/Bob/myZipFile.zip", "-d", "/Users/jt/Desktop/Bob")

Or maybe you can call the unzip command with the flags "-n never overwrite existing files" or "-o overwrite files WITHOUT prompting".

Please let me know if any of these suggestions solve your problem.

Nordeast commented 7 years ago

I am having the same issue here as @patchthecode. The bash command does not seem to ever return.

I can get it to unzip with this command: run(bash: "unzip ./myfile.zip"

If I then put a flag in the command it no longer returns: run(bash: "unzip -a ./myfile.zip" or run(bash: "unzip ./myfile.zip -d ./myfile2

Interestingly those same commands work fine when I use runAndPrint instead: try! runAndPrint(bash: "unzip -a ./myfile.zip" try! runAndPrint(bash: "unzip ./myfile.zip -d ./myfile2"

I am just trying to avoid the console output because its very verbose and doesn't add anything to my script.

kareman commented 7 years ago

What happens if you try let output = "".run(bash: "unzip -a ./myfile.zip")?

Nordeast commented 7 years ago

Yea you are correct it only happens when unzip asks for more input. I thought I was careful to make sure to delete the unzipped file after I was done with it. On a second run of the same script it fails. I was missing a delete of a __MACOSX directory that unzip creates. That was causing unzip to ask for input.

let output = "".run(bash: "unzip -a ./myfile.zip")

Clears the prompt and allows it to continue.

kareman commented 7 years ago

Excellent. I'll close this issue now.

@patchthecode feel free to reopen it if your problem was not resolved.

patchthecode commented 7 years ago

@kareman i'll try it today and let you know