c语言字符串拼接——snprintf

获取可执行文件绝对路径的时候遇到了一个问题,比如给了可执行文件的名字 “ls”,要求在/bin和/usr/bin里面找存在的可执行的名叫ls的可执行文件,返回绝对路径比如/bin/ls,如果高效拼接“/bin”、“/”、“ls”。
image.png
image.png
借鉴上面的回答,得到代码:

  1. char *pathSet[] = {"/bin", "/usr/bin", NULL};
  2. #define BUFF_SIZE 256
  3. int searchPath(char *execute, char *path) {
  4. for (int i = 0; pathSet[i] != NULL; i++) {
  5. snprintf(path, BUFF_SIZE, "%s/%s", pathSet[i], execute);
  6. if (access(path, X_OK) == 0) return 0;
  7. }
  8. return -1;
  9. }

答案(未实现并行指令)

  1. #include <ctype.h> // isspace
  2. #include <regex.h> // regcomp, regexec, regfree
  3. #include <stdio.h> // fopen, fclose, fileno, getline, feof
  4. #include <stdlib.h> // exit
  5. #include <sys/types.h>
  6. #include <sys/wait.h> // waitpid
  7. #include <string.h> // strlen, strsep, strcat, strdup, strcmp
  8. #include <unistd.h> // STDERR_FILENO, fork, exec, access, exit, chdir
  9. #define INTERACTIVE_MODE 1
  10. #define BATCH_MODE 2
  11. #define BUFF_SIZE 256
  12. char *pathSet[BUFF_SIZE] = {"/bin", "/usr/bin", NULL};
  13. char *line = NULL;
  14. FILE *in;
  15. void printError() {
  16. char error_message[30] = "An error has occurred\n";
  17. write(STDERR_FILENO, error_message, strlen(error_message));
  18. }
  19. void parseInputAndExecute(char *arg);
  20. void executeCommands(char *args[], int argsNum, FILE *out);
  21. int searchPath(char *execute, char *path);
  22. void redirect(FILE *out);
  23. char *trim(char *s);
  24. int main(int argc, char *argv[]) {
  25. size_t len = 0;
  26. ssize_t readlen = 0;
  27. char *command = NULL;
  28. //int commandsNum = 0;
  29. if (argc == 1) {
  30. while (1) {
  31. printf("wish> ");
  32. if ((readlen = getline(&line, &len, stdin)) != -1) {
  33. if (line[readlen - 1] == '\n') line[readlen - 1] = '\0';
  34. while ((command = strsep(&line, "&")) != NULL) {
  35. //printf("cmd:%s--line:%s--|", command, line);
  36. if (command[0] == '\0') continue;
  37. parseInputAndExecute(command);
  38. }
  39. } else {
  40. free(line);
  41. printError();
  42. exit(1);
  43. }
  44. }
  45. } else if (argc == 2){
  46. in = fopen(argv[1], "r");
  47. if (in == NULL) {
  48. free(line);
  49. printError();
  50. exit(1);
  51. }
  52. while ((readlen = getline(&line, &len, in)) != -1) {
  53. if (line[readlen - 1] == '\n') line[readlen - 1] = '\0';
  54. while ((command = strsep(&line, "&")) != NULL) {
  55. //printf("cmd:%s--line:%s--|", command, line);
  56. if (command[0] == '\0') continue;
  57. parseInputAndExecute(command);
  58. }
  59. }
  60. fclose(in);
  61. free(line);
  62. exit(0);
  63. } else {
  64. printError();
  65. exit(1);
  66. }
  67. return 0;
  68. }
  69. void parseInputAndExecute(char *arg) {
  70. FILE *out = stdout;
  71. int argsNum = 0;
  72. char *args[BUFF_SIZE];
  73. char *token;
  74. char *command = strsep(&arg, ">");
  75. if (command == NULL || *command == '\0') {
  76. printError();
  77. return;
  78. }
  79. if (arg != NULL) {
  80. // contain white space in the middle or ">"
  81. char *file = trim(arg);
  82. token = strsep(&file, " \t");
  83. //printf("file:%s---token:%s", file, token);
  84. if (file != NULL) {
  85. printError();
  86. return;
  87. }
  88. if ((out = fopen(token, "w")) == NULL) {
  89. printError();
  90. return;
  91. }
  92. }
  93. //printf("command:%s--arg:%s\n", line, arg);
  94. char *const delim = " \t";
  95. command = trim(command);
  96. while (command && *command != '\0') {
  97. token = strsep(&command, delim);
  98. if (token != NULL && *token != '\0') args[argsNum++] = token;
  99. if (argsNum >= BUFF_SIZE) break;
  100. }
  101. // for (int i = 0; i < argsNum; i++) {
  102. // printf("token:%s--argsNum:%d\n", args[i], argsNum);
  103. // }
  104. if (argsNum < BUFF_SIZE) args[argsNum] = NULL;
  105. else args[BUFF_SIZE - 1] = NULL;
  106. if (argsNum > 0) {
  107. executeCommands(args, argsNum, out);
  108. }
  109. }
  110. void executeCommands(char *args[], int argsNum, FILE *out) {
  111. // check built-in command: exit, cd, path
  112. if (strcmp(args[0], "exit") == 0) {
  113. if (argsNum > 1) printError();
  114. else {
  115. free(line);
  116. exit(EXIT_SUCCESS); //exit(0);
  117. }
  118. } else if (strcmp(args[0], "cd") == 0) {
  119. if (argsNum != 2) printError();
  120. else {
  121. if (chdir(args[1]) == -1) {
  122. printError();
  123. }
  124. }
  125. } else if (strcmp(args[0], "path") == 0) {
  126. int i = 0;
  127. // while (args[i]) {
  128. // printf("args:%s\n", args[i]);
  129. // i++;
  130. // }
  131. // i = 0;
  132. while (pathSet[i] != NULL) i++;
  133. int j = 0;
  134. while (j < argsNum - 1) {
  135. pathSet[i] = strdup(args[j + 1]);
  136. i++;
  137. j++;
  138. }
  139. pathSet[i] = NULL;
  140. if (argsNum == 1) pathSet[0] = NULL;
  141. // i = 0;
  142. // while (pathSet[i]) {
  143. // printf("pathset:%s\n", pathSet[i]);
  144. // i++;
  145. // }
  146. } else {
  147. // not built-in command
  148. char path[BUFF_SIZE];
  149. int rc = searchPath(args[0], path);
  150. if (rc == -1) {
  151. printError(); // not fond in path
  152. return;
  153. }
  154. //printf("path: %s,args: %s", path, args[0]);
  155. pid_t pid = fork();
  156. if (pid < 0) {
  157. printError();
  158. exit(1);
  159. } else if (pid == 0) {
  160. redirect(out);
  161. execv(path, args);
  162. printError();
  163. } else {
  164. waitpid(pid, NULL, 0); // parent process waits child
  165. }
  166. }
  167. }
  168. int searchPath(char *execute, char *path) {
  169. for (int i = 0; pathSet[i] != NULL; i++) {
  170. snprintf(path, BUFF_SIZE, "%s/%s", pathSet[i], execute);
  171. int rc = access(path, X_OK);
  172. //printf("path:%s---rc:%d\n", path, rc);
  173. if (rc == 0) {
  174. return 0;
  175. }
  176. }
  177. return -1;
  178. }
  179. void redirect(FILE *out) {
  180. int outFileno = fileno(out);
  181. if (outFileno == -1) {
  182. printError();
  183. exit(1);
  184. }
  185. if (outFileno != STDOUT_FILENO) {
  186. // redirect output
  187. if (dup2(outFileno, STDOUT_FILENO) == -1) {
  188. printError();
  189. return;
  190. }
  191. if (dup2(outFileno, STDERR_FILENO) == -1) {
  192. printError();
  193. return;
  194. }
  195. fclose(out);
  196. }
  197. }
  198. char *trim(char *s) {
  199. // trim leading spaces
  200. while (isspace(*s)) s++;
  201. if (*s == '\0') return s; //empty string
  202. // trim trailing spaces
  203. char *end = s + strlen(s) - 1;
  204. while (end > s && isspace(*end)) end--;
  205. *(end + 1) = '\0';
  206. return s;
  207. }