코코아 앱에서 터미널 명령 실행
단말기 등)를 실행하려면 해야 ?grep
Objective-C 코코아 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★.
하시면 됩니다.NSTask
'는를 들어 보겠습니다/usr/bin/grep foo bar.txt
'
int pid = [[NSProcessInfo processInfo] processIdentifier];
NSPipe *pipe = [NSPipe pipe];
NSFileHandle *file = pipe.fileHandleForReading;
NSTask *task = [[NSTask alloc] init];
task.launchPath = @"/usr/bin/grep";
task.arguments = @[@"foo", @"bar.txt"];
task.standardOutput = pipe;
[task launch];
NSData *data = [file readDataToEndOfFile];
[file closeFile];
NSString *grepOutput = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog (@"grep returned:\n%@", grepOutput);
NSPipe
★★★★★★★★★★★★★★★★★」NSFileHandle
는 태스크의 표준 출력을 리다이렉트하기 위해 사용됩니다.
Objective-C 응용 프로그램에서 운영 체제와 상호 작용하는 방법에 대한 자세한 내용은 Apple의 Development Center에서 다음 문서를 참조하십시오.운영 체제와 상호 작용합니다.
편집: NS Log 문제에 대한 수정이 포함되어 있습니다.
NSTask를 사용하여 bash를 통해 명령줄 유틸리티를 실행하는 경우 NSLog를 계속 작동시키려면 다음 매직라인을 포함해야 합니다.
//The magic line that keeps your log where it belongs
task.standardOutput = pipe;
자세한 것은, https://web.archive.org/web/20141121094204/https://cocoadev.com/HowToPipeCommandsWithNSTask 를 참조해 주세요.
켄트의 기사는 나에게 새로운 아이디어를 주었다.이 runCommand 메서드는 스크립트 파일이 필요하지 않고 한 줄씩 명령을 실행합니다.
- (NSString *)runCommand:(NSString *)commandToRun
{
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
NSArray *arguments = [NSArray arrayWithObjects:
@"-c" ,
[NSString stringWithFormat:@"%@", commandToRun],
nil];
NSLog(@"run command:%@", commandToRun);
[task setArguments:arguments];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
NSData *data = [file readDataToEndOfFile];
NSString *output = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
return output;
}
다음과 같이 사용할 수 있습니다.
NSString *output = runCommand(@"ps -A | grep mysql");
나눔의 정신으로...셸 스크립트를 실행할 때 자주 사용하는 방법입니다.제품 번들에 스크립트를 추가한 후(빌드 복사 단계에서) 런타임에 스크립트를 읽고 실행할 수 있습니다.주의: 이 코드는 privateFrameworks 서브패스에서 스크립트를 찾습니다.경고: 이것은 도입된 제품의 보안 리스크가 될 수 있지만 사내 개발에서는 애플리케이션을 다시 컴파일하지 않고 번들 내의 셸 스크립트를 편집하는 것만으로 간단한 커스터마이즈(rsync 대상 호스트 등)를 할 수 있습니다.
//------------------------------------------------------
-(void) runScript:(NSString*)scriptName
{
NSTask *task;
task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/sh"];
NSArray *arguments;
NSString* newpath = [NSString stringWithFormat:@"%@/%@",[[NSBundle mainBundle] privateFrameworksPath], scriptName];
NSLog(@"shell script path: %@",newpath);
arguments = [NSArray arrayWithObjects:newpath, nil];
[task setArguments: arguments];
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
NSFileHandle *file;
file = [pipe fileHandleForReading];
[task launch];
NSData *data;
data = [file readDataToEndOfFile];
NSString *string;
string = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
NSLog (@"script returned:\n%@", string);
}
//------------------------------------------------------
편집: NS Log 문제에 대한 수정이 포함되어 있습니다.
NSTask를 사용하여 bash를 통해 명령줄 유틸리티를 실행하는 경우 NSLog를 계속 작동시키려면 다음 매직라인을 포함해야 합니다.
//The magic line that keeps your log where it belongs
[task setStandardInput:[NSPipe pipe]];
컨텍스트:
NSPipe *pipe;
pipe = [NSPipe pipe];
[task setStandardOutput: pipe];
//The magic line that keeps your log where it belongs
[task setStandardInput:[NSPipe pipe]];
자세한 것은, http://www.cocoadev.com/index.pl?NSTask 를 참조해 주세요.
Swift로 하는 방법은 다음과 같습니다.
Swift 3.0의 변경 사항:
NSPipe
been has has has has has 。Pipe
NSTask
been has has has has has 。Process
이는 상기 Inkit의 Objective-C 답변을 기반으로 합니다.그는 그것을 에 대한 카테고리로 썼다.NSString
- Swift의 경우, 이는String
.
확장 String.runAsCommand() -> 문자열
extension String {
func runAsCommand() -> String {
let pipe = Pipe()
let task = Process()
task.launchPath = "/bin/sh"
task.arguments = ["-c", String(format:"%@", self)]
task.standardOutput = pipe
let file = pipe.fileHandleForReading
task.launch()
if let result = NSString(data: file.readDataToEndOfFile(), encoding: String.Encoding.utf8.rawValue) {
return result as String
}
else {
return "--- Error running command - Unable to initialize string from file data ---"
}
}
}
사용방법:
let input = "echo hello"
let output = input.runAsCommand()
print(output) // prints "hello"
또는 그냥:
print("echo hello".runAsCommand()) // prints "hello"
예:
@IBAction func toggleFinderShowAllFiles(_ sender: AnyObject) {
var newSetting = ""
let readDefaultsCommand = "defaults read com.apple.finder AppleShowAllFiles"
let oldSetting = readDefaultsCommand.runAsCommand()
// Note: the Command results are terminated with a newline character
if (oldSetting == "0\n") { newSetting = "1" }
else { newSetting = "0" }
let writeDefaultsCommand = "defaults write com.apple.finder AppleShowAllFiles \(newSetting) ; killall Finder"
_ = writeDefaultsCommand.runAsCommand()
}
해 주세요.Process
되다Pipe
는 입니다.NSString
일 수도 에러 문자열일 수도 .NSString
.
0이 Swift로 할 수 .String
리고돌돌 돌돌돌다다
로든 no가 경우NSString
파일 데이터에서 초기화할 수 있으며 함수는 오류 메시지를 반환합니다.는 임의의 되었을 수 .String?
하지만, 그것은 사용하기 불편할 것이고 이것이 일어날 가능성이 매우 낮기 때문에 유용한 목적을 제공하지 못할 것이다.
Objective-C(Swift의 경우 아래 참조)
상위 답변의 코드를 정리하여 읽기 쉽고 용장성이 떨어지도록 하고, 한 줄짜리 방식의 장점을 추가하여 NSString 카테고리로 만들었다.
@interface NSString (ShellExecution)
- (NSString*)runAsCommand;
@end
구현:
@implementation NSString (ShellExecution)
- (NSString*)runAsCommand {
NSPipe* pipe = [NSPipe pipe];
NSTask* task = [[NSTask alloc] init];
[task setLaunchPath: @"/bin/sh"];
[task setArguments:@[@"-c", [NSString stringWithFormat:@"%@", self]]];
[task setStandardOutput:pipe];
NSFileHandle* file = [pipe fileHandleForReading];
[task launch];
return [[NSString alloc] initWithData:[file readDataToEndOfFile] encoding:NSUTF8StringEncoding];
}
@end
사용방법:
NSString* output = [@"echo hello" runAsCommand];
출력 부호화에 문제가 있는 경우:
// Had problems with `lsof` output and Japanese-named files, this fixed it
NSString* output = [@"export LANG=en_US.UTF-8;echo hello" runAsCommand];
미래의 나처럼 당신에게도 도움이 되었으면 좋겠어요. (안녕하세요!)
스위프트 4
Swift의 예가 .Pipe
,Process
, , , , 입니다.String
extension String {
func run() -> String? {
let pipe = Pipe()
let process = Process()
process.launchPath = "/bin/sh"
process.arguments = ["-c", self]
process.standardOutput = pipe
let fileHandle = pipe.fileHandleForReading
process.launch()
return String(data: fileHandle.readDataToEndOfFile(), encoding: .utf8)
}
}
사용방법:
let output = "echo hello".run()
목적 C의 특정 방법을 찾고 있지 않다면 fork, exec 및 wait를 사용할 수 있습니다. fork
는 현재 중인 프로그램의 .「복사」는, 「 」 。exec
는 현재 중인 새 하고 "는 새로운 프로그램으로 대체됩니다.wait
는 서브프로세스가 종료될 때까지 기다립니다.를에에에에에에 ( )
#include <stdlib.h>
#include <unistd.h>
pid_t p = fork();
if (p == 0) {
/* fork returns 0 in the child process. */
execl("/other/program/to/run", "/other/program/to/run", "foo", NULL);
} else {
/* fork returns the child's PID in the parent. */
int status;
wait(&status);
/* The child has exited, and status contains the way it exited. */
}
/* The child has run and exited by the time execution gets to here. */
셸의 명령줄에서 입력한 것처럼 명령을 실행하는 시스템도 있습니다.더 간단하지만 상황을 통제할 수 있는 능력이 떨어집니다.
하고 있을 링크는 로 되어 입니다.의た 、 Apple 、 Apple 、 의의의의의의의모모모모POSIX
포식스
오래된 POSIX 시스템("echo -en "\007")도 있습니다.
를 쓴 는 'C'가 'C'이기 때문입니다.NSTask
★★★★★★★★…
NSString * runCommand(NSString* c) {
NSString* outP; FILE *read_fp; char buffer[BUFSIZ + 1];
int chars_read; memset(buffer, '\0', sizeof(buffer));
read_fp = popen(c.UTF8String, "r");
if (read_fp != NULL) {
chars_read = fread(buffer, sizeof(char), BUFSIZ, read_fp);
if (chars_read > 0) outP = $UTF8(buffer);
pclose(read_fp);
}
return outP;
}
NSLog(@"%@", runCommand(@"ls -la /"));
total 16751
drwxrwxr-x+ 60 root wheel 2108 May 24 15:19 .
drwxrwxr-x+ 60 root wheel 2108 May 24 15:19 ..
…
오, 그리고 완전하기 위해서/명확하기 위해서…
#define $UTF8(A) ((NSString*)[NSS stringWithUTF8String:A])
년 후, 몇년,,는C
아직도 혼란스러운 상황이야그리고 위의 중대한 결점을 고칠 수 있는 나의 능력에 대해 거의 신뢰하지 않고 - 내가 제안하는 유일한 올리브 브랜치는 순수한 동료/장황한 사람들을 위해 뼈만 남은 @inket의 대답을 재작성하는 것이다.
id _system(id cmd) {
return !cmd ? nil : ({ NSPipe* pipe; NSTask * task;
[task = NSTask.new setValuesForKeysWithDictionary:
@{ @"launchPath" : @"/bin/sh",
@"arguments" : @[@"-c", cmd],
@"standardOutput" : pipe = NSPipe.pipe}]; [task launch];
[NSString.alloc initWithData:
pipe.fileHandleForReading.readDataToEndOfFile
encoding:NSUTF8StringEncoding]; });
}
몇 다음 하고, 이 명령어의 합니다.[file readDataToEndOfFile]
.
- (void)runCommand:(NSString *)commandToRun
{
NSTask *task = [[NSTask alloc] init];
[task setLaunchPath:@"/bin/sh"];
NSArray *arguments = [NSArray arrayWithObjects:
@"-c" ,
[NSString stringWithFormat:@"%@", commandToRun],
nil];
NSLog(@"run command:%@", commandToRun);
[task setArguments:arguments];
NSPipe *pipe = [NSPipe pipe];
[task setStandardOutput:pipe];
NSFileHandle *file = [pipe fileHandleForReading];
[task launch];
[self performSelectorInBackground:@selector(collectTaskOutput:) withObject:file];
}
- (void)collectTaskOutput:(NSFileHandle *)file
{
NSData *data;
do
{
data = [file availableData];
NSLog(@"%@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] );
} while ([data length] > 0); // [file availableData] Returns empty data when the pipe was closed
// Task has stopped
[file closeFile];
}
Custos Mortem은 다음과 같이 말했다.
아무도 통화 차단/비차단 문제에 관여하지 않았다니 놀랍다
에 관한 콜의 블로킹/비블로킹에 관한 문제의 경우NSTask
이하를 참조해 주세요.
asynctask.m - NSTask를 사용하여 데이터를 처리하기 위해 비동기 stdin, stdout 및 stderr 스트림을 구현하는 방법을 나타내는 샘플코드
asynctask.m의 소스 코드는 GitHub에서 구할 수 있습니다.
또는 목표 C는 위에 OO 레이어가 있는 C이기 때문에 Posix Conterparts를 사용할 수 있습니다.
int execl(const char *path, const char *arg0, ..., const char *argn, (char *)0);
int execle(const char *path, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
int execlp(const char *file, const char *arg0, ..., const char *argn, (char *)0);
int execlpe(const char *file, const char *arg0, ..., const char *argn, (char *)0, char *const envp[]);
int execv(const char *path, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int execvp(const char *file, char *const argv[]);
int execvpe(const char *file, char *const argv[], char *const envp[]);
unistd에서 포함되어 있습니다.h 헤더 파일
Terminal 명령어로 관리자 권한(일명 '관리자 권한')이 필요한 경우sudo
), 사용AuthorizationExecuteWithPrivileges
대신.다음으로 "com.stackoverflow.test"라는 이름의 파일이 생성됩니다.이 파일은 루트 디렉토리 "/System/Library/Caches"입니다.
AuthorizationRef authorizationRef;
FILE *pipe = NULL;
OSStatus err = AuthorizationCreate(nil,
kAuthorizationEmptyEnvironment,
kAuthorizationFlagDefaults,
&authorizationRef);
char *command= "/usr/bin/touch";
char *args[] = {"/System/Library/Caches/com.stackoverflow.test", nil};
err = AuthorizationExecuteWithPrivileges(authorizationRef,
command,
kAuthorizationFlagDefaults,
args,
&pipe);
언급URL : https://stackoverflow.com/questions/412562/execute-a-terminal-command-from-a-cocoa-app
'IT' 카테고리의 다른 글
Larabel에서 Excel로 Excel을 내보낼 때 어떻게 열 헤더를 포함할 수 있습니까? (0) | 2023.04.23 |
---|---|
T-SQL을 사용하여 두 정수 값을 나누어 부동 결과를 얻는 방법은 무엇입니까? (0) | 2023.04.23 |
뷰가 숨겨져 있을 때 자동 레이아웃을 사용하여 다른 뷰를 이동하는 방법은 무엇입니까? (0) | 2023.04.23 |
SQL에서 조회할 매개 변수를 전달하는 방법(Excel) (0) | 2023.04.23 |
T-SQL에 해당하는 분할 함수? (0) | 2023.04.23 |