POSIX 명령을 Objective-C에서 사용하려고 시도 착오했다.

개요



이번에는 예로서 POSIX 명령의 chflags를 사용하여 아래 폴더의 파일을 숨겨진 파일로 만드는 것을 생각해 보자.



chflags 통행은 /usr/bin/chflags 이다.


명령
설명


chflags hidden <파일 이름>
숨겨진 속성 부여

chflags nohidden <파일 이름>
숨겨진 속성을 취하다


터미널에서 전화하는 방법은 다음과 같습니다. ( ~ 에 자신의 환경 경로를 삽입)

터미널에서 실행 예
chflags hidden ~/Downloads/instance/SampleFolder/sample.txt

구현



이것과 같은 Objective-C의 코드로, NSTask를 사용해 실행한다.

호출부
NSString *sampleFilePathWithTilde = @"~/Downloads/instance/SampleFolder/sample.txt";
NSString *sampleFilePath          = [sampleFilePathWithTilde stringByExpandingTildeInPath];

NSURL *chflags = [NSURL fileURLWithPath:@"/usr/bin/chflags"];
[self executeSelectCommand:chflags args:@[@"hidden", sampleFilePath]];

함수 부분
/**
 @brief  POSIXコマンドのパスとオプションを格納した配列を渡して実行する
 @param  commandURL POSIXコマンドのパス args 引数
 @return 正常終了でYES
 */
- (BOOL)executeSelectCommand:(NSURL *)commandURL args:(NSArray *)args {
    // タスクオブジェクトを準備する
    NSTask *task = [[NSTask alloc] init];
    [task setLaunchPath:[commandURL path]];
    [task setArguments:args];

    // 読み込み元のパイプを作成する
    NSPipe *outPipe = [[NSPipe alloc] init];
    [task setStandardOutput:outPipe];

    // プロセスを起動する
    [task launch];

    // タスクが正常に終了することを確認する
    [task waitUntilExit];
    int status = [task terminationStatus];

    // ステータスを確認する
    if (status != 0) {
        return NO;
    }
    return YES;
}

실행 후, 숨겨진 속성이 되어 있는 것을 확인.



위 코드 개선


SampleFolder 내의 파일을 모두 숨겨진 속성으로 하려고 한다.
터미널에서 전화하는 방법은 다음과 같습니다. ( ~ 에 자신의 환경 경로를 삽입)

터미널에서 실행 예
chflags hidden ~/Downloads/instance/SampleFolder/*

그러나 같은 것을 상기의 코드로 행하려고 하면, 와일드 카드인 「*」를 전개할 수 없다고 하는 불편이 생긴다.
[self executeSelectCommand:chflags args:@[@"hidden", @"*"]];

로그
chflags: *: No such file or directory

디렉토리를 찾을 수 없다는 오류.
「*」를 전개할 수 없는 것 같다.

문제에 대해 자세히 알아보기


  • shell을 통과하면, *를 전개할 수 있다는 것.
  • h tps : // s t c ゔ ぇ rf ぉ w. 코 m / 쿠에 s 치온 s / 38337724 / 우신 g
  • 【Linux】 커맨드 라인에서 「*」등의 와일드 카드를 사용하는 경우에 조심하는 것 【쉘】


  • NSTask doesn't expand the * in your path. But if you invoke the command through the shell (i.e./bin/bash), it will:
  • 또 POSIX 커멘드의 풀 패스 지정도 번거롭다. 이것도 Shell을 통해 해결할 수 있다.
    - NSTask에서 외부 명령을 실행할 때 "/bin/sh -c"를 통과하면 행복합니다.

  • NSTask에서 외부 명령을 실행하는 경우 외부 명령을 전체 경로로 지정해야 한다. 머신 환경에 따라 커맨드는 머신에 의해 "/opt/local/bin"이거나 "/usr/local/bin"이기 때문에, 풀 패스로 커멘드를 지정하면 움직이지 않기 때문에, "/bin/sh -c"를 통해 명령의 실행 경로를 해결하면 행복하게 될 것 같습니다.
  • 이상으로부터, 이하와 같이 손을 가했다.
  • 보다 터미널의 조작에 가까운 형태로 호출할 수 있도록(듯이) 인수를 변경.
  • 첫번째 인수는 NSArray 에서 NSString 로 했다.
  • 두 번째 인수는 명령을 실행하기 전에 cd 그리고 현재 경로를 변경하는 것과 동의어.

  • POSIX 명령의 호출에 Shell을 통과시키게 했다.


  • 개선 후 구현



    호출부
    NSString *sampleFolderPathWithTilde = @"~/Downloads/instance/SampleFolder";
    NSString *sampleFolderPath          = [sampleFolderPathWithTilde stringByExpandingTildeInPath];
    NSURL    *sampleFolderURL           = [NSURL fileURLWithPath:sampleFolderPath];
    [self executePosixThroughBashWithStatement:@"chflags hidden *" posixExecutingURL:sampleFolderURL];
    

    함수 부분
    /**
     @brief Shellを通じてPosixコマンドを実行する(*を展開するために用意)
     @param statement 引数の文字列 ex.@"chflags hidden *"
     @param aCurrentDirectory Posixコマンドの実行上のパス(空文字可)
     @return BOOL Posix実行正常終了でYES
     */
    - (BOOL)executePosixThroughBashWithStatement:(NSString *)statement posixExecutingURL:(NSURL *)aCurrentDirectory {
        NSArray *args = @[@"-c", statement];
    
        // タスクオブジェクトを準備する
        NSTask *task = [[NSTask alloc] init];
        task.launchPath = @"/bin/sh"; // ワイルドカードを展開するためbashを経由する
        task.arguments  = args;
        // 読み込み元のパイプを作成する
        NSPipe *pOutput = [NSPipe pipe];  // 標準出力先
        NSPipe *pError  = [NSPipe pipe];  // エラー出力先
        task.standardOutput = pOutput;
        task.standardError  = pError;
        if (aCurrentDirectory.path.length != 0) {
            task.currentDirectoryURL = aCurrentDirectory;
        }
    
        // プロセスを起動する
        [task launch];
        // タスクが正常に終了することを確認する
        [task waitUntilExit];
    
        NSData *dataError = [[pError fileHandleForReading] availableData]; //エラーのデータ
        if (dataError.length != 0) {
            NSLog(@"error-%s", [dataError bytes]); //エラー出力
        }
    
        NSData   *dataOutput   = [[pOutput fileHandleForReading] availableData];    //標準出力データ
        NSString *stringOutput = [[NSString alloc] initWithData:dataOutput encoding:NSShiftJISStringEncoding]; //標準出力
        if (stringOutput.length != 0) {
            NSLog(@"\n*** UnixOutput ***\n%@", stringOutput);
        }
    
        // ステータスを確認する
        if ([task terminationStatus] != 0) {
            return NO;
        }
        return YES;
    }
    

    모두 숨겨진 속성이 되어 있는 것을 확인.



    첫 번째 인수이지만 arguments 의 요소를 소분으로 하면 잘 가지 않았으므로 NSString 로 다시 작성했다.
    NSArray *args = @[@"-c", @"chflags hidden *"];
    

    아래 코드에서 실행했는데 오류가 발생했습니다. (처음의 예에서는 잘 가고 있었지만 왜일까)
    NSArray *args = @[@"-c", @"chflags", @"hidden", @"*"];
    

    오류 로그
    error-usage: chflags [-fhv] [-R [-H | -L | -P]] flags file ...
    G…
    

    여담:로그에의 아웃풋등은 반환값으로 하거나 하는 편이, 디버그하기 쉬울지도 모른다고 생각한다.

    좋은 웹페이지 즐겨찾기