Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Technologx

macrumors member
Original poster
Dec 17, 2014
51
4
USA
I want to create a app kind of like Ds Store Remover but it will remove directories instead of just one file. So I was wondering how do I go about doing this I have a bash script the code is below I just need to know what to do. To have the app ask for root password and allow the user to select the directory that they want these directories.



sudo rm -rf “.Thrashes”





sudo rm -rf “.Spotlight-V100”





sudo rm -rf “.Trash”





sudo rm -rf “.DS_Store”
 
I want to create a app kind of like Ds Store Remover but it will remove directories instead of just one file. So I was wondering how do I go about doing this I have a bash script the code is below I just need to know what to do. To have the app ask for root password and allow the user to select the directory that they want these directories.

sudo rm -rf “.Thrashes”
sudo rm -rf “.Spotlight-V100”
sudo rm -rf “.Trash”
sudo rm -rf “.DS_Store”

It sounds like you simply want to run your bash script as an application. I'd do this by rewriting it in Applescript:

Code:
set TargetDir to (choose folder with prompt "Choose the folder you want to clean")
set TargetPath to POSIX path of TargetDir
set ShellScript to "cd " & TargetPath & "
rm -rf .Trashes
rm -rf .Spotlight-V100
rm -rf .Trash
rm -rf .DS_Store"
do shell script ShellScript with administrator privileges

You can then do File -> Save... and choose Application as the file format.

Note that doing it this way lets the operating system deal with granting root permissions - it doesn't mess around with handling passwords itself.

BE VERY CAREFUL. If the cd command fails for any reason then the rm commands will carry on regardless, most likely in /. It would probably be a good idea to get the bash script to exit if the cd fails.
 
...or alternatively, if you *really* want to do it in Automator (and there's no reason why you shouldn't) then just select "Application" when you create a new Automator action and use the Run Shell Script action.
 
BE VERY CAREFUL. If the cd command fails for any reason then the rm commands will carry on regardless, most likely in /. It would probably be a good idea to get the bash script to exit if the cd fails.

If you separate the bash commands with && symbols, the sequence will stop if any command fails:

command1 && command2 && command3
 
  • Like
Reactions: nightcap965
How would I make this into a actual app using Xcode?

Not sure why you'd need to make it into an Xcode app, to be honest. However, you have a few options, including:

• Rewrite it in Objective-C / Swift and use NSTask to execute your shell scripts (http://www.raywenderlich.com/36537/nstask-tutorial)
• Create an AppleScriptObjC app and use the code you already have
• Rewrite it in pure Objective-C from scratch

...and I'm sure someone will recommend using Python at some point. I'm not going to though. ;-)
 
What line of code do I need to prompt user for the root password because of su?
 
What line of code do I need to prompt user for the root password because of su?
It's done by this line of AppleScript:
Code:
do shell script ShellScript with administrator privileges
The with administrator privileges will prompt for a password using a dialog, and run the shell script as root if it gets the right info.

As a test, I recommend that you run a completely harmless shell script with administrator privileges, so you can see how it works. An example would be the 'id' shell command, with output redirected to a safe file.
 
Possibly not relevant, but I feel worth having on record:

If you're ever going to try to distribute your app then it's always always always worth managing authentication by letting the operating system deal with it (such as by declaring with administrator privileges in Applescript). If I were to get a dialog box asking for any system password (let alone for an account with sudo privileges) from anything other than the OS itself, I wouldn't be using that app again.

If you're just using the app yourself then you can do what you like if it's easier. Who cares if it looks suspicious? In this case I'd argue that it's actually easier to run the script as an administrator legitimately than to mess around trying to pass passwords to sudo, but that's your choice.
 
I figured out how to create the app with Xcode but I need to have the app promt for a root password after the directory is selected.
 
I figured out how to create the app with Xcode but I need to have the app promt for a root password after the directory is selected.

I assume you're using Swift. From here, you could do something like:

Code:
func doScriptWithAdmin(inScript:String) -> String{
    let script = "do shell script \"\(inScript)\" with administrator privileges"
    var appleScript = NSAppleScript(source: script)
    var eventResult = appleScript.executeAndReturnError(nil)
    if !eventResult {
        return "ERROR"
    }else{
        return eventResult.stringValue
    }
}

Then just pass your script (without sudo calls) to that function.
 
I assume you're using Swift. From here, you could do something like:

Code:
func doScriptWithAdmin(inScript:String) -> String{
    let script = "do shell script \"\(inScript)\" with administrator privileges"
    var appleScript = NSAppleScript(source: script)
    var eventResult = appleScript.executeAndReturnError(nil)
    if !eventResult {
        return "ERROR"
    }else{
        return eventResult.stringValue
    }
}

Then just pass your script (without sudo calls) to that function.

Actually this is what I got:
Code:
- (IBAction)browse:(id)sender{


   

   

    NSOpenPanel* openDlg = [NSOpenPanelopenPanel];

   

    // Enable the selection of files in the dialog.

    [openDlg setCanChooseFiles:NO];

   

    // Enable the selection of directories in the dialog.

    [openDlg setCanChooseDirectories:YES];

   

    // Change "Open" dialog button to "Select"

    [openDlg setPrompt:@"Select"];

   

    // Display the dialog.  If the OK button was pressed,

    // process the files.

    if ( [openDlg runModal] == NSModalResponseOK )

    {

        // Get an array containing the full filenames of all

        // files and directories selected.

        NSArray* files = [openDlg URLs];

       

        // Loop through all the files and process them.

        for( int i = 0; i < [files count]; i++ )

        {

           

            NSString* fileName = [files objectAtIndex:i];

            NSLog(@"file: %@", fileName);

           

            NSTask *task = [[NSTaskalloc] init];

            [task setLaunchPath:@"/bin/bash"];

            [task setArguments:@[@"-c", @"/usr/local/bin/hiddenfileremover"]];

            [task launch];

           

            [openDlg setPrompt:@"Select"];


        }

    }

}
 
This is the script that the app will be running:

Code:
#!/bin/bash

sudo rm -rf .Trashes

sudo rm -rf .Spotlight-V100

sudo rm -rf .DS_Store

sudo rm -rf .fseventsd
 
Right, I haven't tested any of this myself, but hopefully these couple of thoughts will help:

1) When getting the filepath of the directory, you should be doing:

Code:
NSString* fileName = [[files objectAtIndex:i] path];

This will get you a proper POSIX filepath instead of a quoted URL path (pretty sure that files is an array of NSURL objects - if not this will need to be something else).

2) Because you have the shebang (#!/bin/bash) in your script, you don't need to invoke bash to run it. The system can do that itself. This code:

Code:
NSTask *task = [[NSTaskalloc] init];
[task setLaunchPath:@"/bin/bash"];
[task setArguments:@[@"-c", @"/usr/local/bin/hiddenfileremover"]];
[task launch];

should be rewritten as:

Code:
NSTask *task = [[NSTaskalloc] init];
[task setLaunchPath:@"/usr/local/bin/hiddenfileremover"];
[task setArguments:@[fileName]];
[task launch];

and your script rewritten as:

Code:
#!/bin/bash
rm -rf $1/.Trashes
rm -rf $1/.Spotlight-V100
rm -rf $1/.DS_Store
rm -rf $1/.fseventsd

(Slashes might need to be removed, or you might need to strip trailing slashes from fileName. You can experiment with that yourself.)


3) If you add this class to your project: https://github.com/sveinbjornt/STPrivilegedTask then you can simply replace your NSTask with an STPrivelegedTask:

Code:
STPrivilegedTask *privilegedTask = [[STPrivilegedTask alloc] init];
[privilegedTask setLaunchPath:@"/usr/local/bin/hiddenfileremover"];
NSArray *args = [NSArray arrayWithObject:fileName];
[privilegedTask setArguments:args];

OSStatus err = [privilegedTask launch];
if (err != errAuthorizationSuccess) {
    if (err == errAuthorizationCanceled) {
        NSLog(@"User cancelled");
    } else {
        NSLog(@"Something went wrong");
    }
} else {
    // task successfully launched
}

and that will run the task as root.
 
How would I add this to my code I'm getting all kinds of errors, sorry I'm new to Mac coding?

Code:
NSString* fileName = [[files objectAtIndex:i] path];
should replace
Code:
NSString* fileName = [files objectAtIndex:i];



and:

Code:
STPrivilegedTask *privilegedTask = [[STPrivilegedTask alloc] init];
[privilegedTask setLaunchPath:@"/usr/local/bin/hiddenfileremover"];
NSArray *args = [NSArray arrayWithObject:fileName];
[privilegedTask setArguments:args];

OSStatus err = [privilegedTask launch];
if (err != errAuthorizationSuccess) {
    if (err == errAuthorizationCanceled) {
        NSLog(@"User cancelled");
    } else {
        NSLog(@"Something went wrong");
    }
} else {
    // task successfully launched
}

should replace:

Code:
NSTask *task = [[NSTaskalloc] init];
[task setLaunchPath:@"/bin/bash"];
[task setArguments:@[@"-c", @"/usr/local/bin/hiddenfileremover"]];
[task launch];

And you'll need to download STPrivelegedTask.h and STPrivelegedTask.m from here and add
Code:
#import "STPrivilegedTask.h"
to the top of your code.

I wasn't expecting this thread to turn to Objective C, which I'll admit is out of my comfort zone. If you get any errors it would be helpful if you could post them.
 
Alright I did what you said now I'm getting this as a error:
Use of undeclared identifier ‘NSOpenPaneopenPanel'
for this line:
Code:
NSOpenPanel* openDlg = [NSOpenPanelopenPanel];
.
 
Alright I did what you said now I'm getting this as a error: for this line:
Code:
NSOpenPanel* openDlg = [NSOpenPanelopenPanel];
.

There should be a space between NSOpenPanel and openPanel.
Code:
NSOpenPanel* openDlg = [NSOpenPanel openPanel];
 
  • Like
Reactions: Technologx
Alright that code is working it's just I need to get my bash script working correctly it's not deleting the files like it should. Do I possibly need to link any frameworks?
 
Alright that code is working it's just I need to get my bash script working correctly it's not deleting the files like it should. Do I possibly need to link any frameworks?

You shouldn't need to link in anything else. It could be any number of things wrong - your script not being called properly or a bad filepath being passed to it, for example.

Did you remember to remove the sudo commands? Leaving them in may cause the script to fail.

I can't really debug this for you. You already have solutions in Applescript (post #2) and Automator (post #3) for the problem you originally asked about. If you're trying to use Xcode for this as a learning exercise, I'd recommend finding some tutorial exercises online instead of inventing your own.
 
You shouldn't need to link in anything else. It could be any number of things wrong - your script not being called properly or a bad filepath being passed to it, for example.

Did you remember to remove the sudo commands? Leaving them in may cause the script to fail.

I can't really debug this for you. You already have solutions in Applescript (post #2) and Automator (post #3) for the problem you originally asked about. If you're trying to use Xcode for this as a learning exercise, I'd recommend finding some tutorial exercises online instead of inventing your own.

Yea I remembered to remove the sudo commands from the script and linked the script correctly. If I was to include the script with the app if I do that how would I go about linking it then?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.