
저는 쉘 스크립팅을 처음 사용합니다. 나는 C 프로그램을 호출하는 Unix 스크립트를 작성하고 싶습니다 N= 2^{i}
. i= 1,2 ....20
나중에 이 데이터를 파일에 기록합니다.
(이 프로그램은 C에서 사다리꼴 법칙을 사용하여 정적분을 계산하고 N항마다 반복 결과와 오차를 반환합니다.)
방금 C를 배우기 시작하면서 사다리꼴 규칙에 대한 코드를 작성했습니다.
#include<stdio.h>
#include<math.h>
#define PI 3.14159265358979323846
float fn(float x)
{
float integrand;
integrand = (1.0/(1.0+x*x));
return integrand;
}
int main()
{
int i,N;
float a,b,sum=0,result=0,h;
float error;
printf("Enter the no of equally spaced points =");
scanf("%d",&N);
printf("Enter the lower limit=");
scanf("%f",&a);
printf("Enter the upper limit=");
scanf("%f",&b);
h=(b-a)/(N-1);
for(i=1;i<=N;i++)
{
sum=sum+fn(a+i*h);
result=(fn(a)+fn(b)+2*sum)*h/2;
error = fabs((atan(b)-atan(a))-result);
//error = PI/2.0 - result;
printf("N=%d result=%f error=%f\n", i, result, error);
}
printf("final result =%f\n", result);
printf("cumulative error =%f\n", error);
}
나는 이 코드를 다음과 같이 실행한다.
gcc -o err.o trap_error.c -lm
내 gcc 버전은gcc (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609
인터넷을 통해 무작위로 검색했지만 유용한 정보를 찾지 못했습니다. 코드도 수정해야 할 것 같습니다. Unix 스크립트 작성을 도와주고 나중에 출력을 파일로 리디렉션할 수 있다면 말이죠 .txt
. 설명된 줄이 포함된 Unix 스크립트는 매우 도움이 될 것입니다.
답변1
사용자에게 메시지를 표시하고 표준 입력에서 매개변수를 읽는 대신 다음을 수용해야 합니다.유닉스 철학, 대신 명령줄 매개변수를 사용하세요.
다음 예제는 내가 선호하는 매개변수 검사 기능을 보여주고 싶었기 때문에 약간 깁니다. scanf()
함수군은 오버플로를 확인하지 않으므로 strto*()
사용해야 합니다. 또한 숫자 뒤에 쓰레기가 있는 경우도 있습니다(예: '121' 대신 '12l'이 마지막 문자 L임). 개인적으로 잡아보고 싶은 부분입니다.
#include <stdlib.h>
#include <locale.h>
#include <ctype.h>
#include <stdio.h>
#include <errno.h>
/* Helper function to parse a double.
* Returns 0 if successful, nonzero otherwise.
*/
static int parse_double(const char *s, double *v)
{
const char *end;
double val;
if (!s)
return errno = EINVAL;
end = s;
errno = 0;
val = strtod(s, (char **)&end);
if (errno)
return errno;
if (!end || end == s)
return errno = EINVAL;
while (*end != '\0' && isspace(*end))
end++;
if (*end != '\0')
return errno = EINVAL;
if (v)
*v = val;
return 0;
}
/* Helper function to parse a long.
* Returns 0 if successful, nonzero otherwise.
*/
static int parse_long(const char *s, long *v)
{
const char *end;
long val;
if (!s)
return errno = EINVAL;
end = s;
errno = 0;
val = strtol(s, (char **)&end, 0);
if (errno)
return errno;
if (!end || end == s)
return errno = EINVAL;
while (*end != '\0' && isspace(*end))
end++;
if (*end != '\0')
return errno = EINVAL;
if (v)
*v = val;
return 0;
}
위의 parse_long()
10진수( 987
), 16진수( 0x3DB
), 8진수( 01733
) 표기를 지원합니다.
그러면 main()
다음과 같습니다
int main(int argc, char *argv[])
{
double min, max;
long n;
setlocale(LC_ALL, "");
/* Require "command N min max" -- four parameters,
* including the executable file name (argv[0]). */
if (argc != 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s N min max\n", argv[0]);
return EXIT_FAILURE;
}
if (parse_long(argv[1], &n) || n < 1L) {
fprintf(stderr, "%s: Invalid N.\n", argv[1]);
return EXIT_FAILURE;
}
if (parse_double(argv[2], &min)) {
fprintf(stderr, "%s: Invalid minimum.\n", argv[2]);
return EXIT_FAILURE;
}
if (parse_double(argv[3], &max)) {
fprintf(stderr, "%s: Invalid maximum.\n", argv[3]);
return EXIT_FAILURE;
}
if (min > max) {
const double tmp = min;
min = max;
max = tmp;
}
/* ... */
return EXIT_SUCCESS;
}
이는 setlocale(LC_ALL, "");
C 라이브러리에 현재 환경을 검사하고 그에 맞게 지역화를 설정하도록 지시합니다. 이 프로그램은 LC_CTYPE
클래스만 사용하여 어떤 문자가 공백(공백 또는 탭)인지 확인합니다. 그럼에도 불구하고 시작하는 것이 좋습니다. 어느 시점에서 ä
및 같은 문자를 지원하려는 경우 €
와이드 문자 및 I/O로 전환할 수 있습니다.
학습자는 parse_long()
및 를 생략하고 절 parse_double()
에서 로 대체하고 현지화를 무시할 수 있습니다. 몇 줄을 절약할 수 있습니다.if
sscanf()
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
double min, max;
long n;
/* Require "command N min max" -- four parameters,
* including the executable file name (argv[0]). */
if (argc != 4 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s N min max\n", argv[0]);
return EXIT_FAILURE;
}
if (sscanf(argv[1], " %ld", &n) != 1 || n < 1L) {
fprintf(stderr, "%s: Invalid N.\n", argv[1]);
return EXIT_FAILURE;
}
if (sscanf(argv[2], " %lf", &min) != 1) {
fprintf(stderr, "%s: Invalid minimum.\n", argv[2]);
return EXIT_FAILURE;
}
if (sscanf(argv[3], " %lf", &max) != 1) {
fprintf(stderr, "%s: Invalid maximum.\n", argv[3]);
return EXIT_FAILURE;
}
if (min > max) {
const double tmp = min;
min = max;
max = tmp;
}
/* ... */
return EXIT_SUCCESS;
}
하지만 제 생각에는 왜 실제로는 충분하지 않은 방법을 배우는 걸까요? 나는 개인적으로 다음과 같은 어리석은 가정이 있는 경우를 알고 있습니다."사람 이름에는 A부터 Z까지의 문자만 포함됩니다."해결하는 데 수십 시간이 걸렸습니다(영어가 아닌 이름을 가진 사용자가 있는 컴퓨팅 클러스터의 411 서비스). 우리는 글로벌 세상에 살고 있습니다. 영어를 구사하는 여러분은 이미 줄을 서서 어리석은 가정을 버리는 것이 좋습니다.
나중에도 현지화를 배울 수 있는 것 같지는 않습니다. 내가 만난 대부분의 "경험이 풍부한 C 프로그래머"는 현지화나 문자 집합 문제에 대해 전혀 알지도 관심도 없는 것 같습니다. (글쎄, 그 이상어디서나 UTF-8 사용.) 이는 다른 사람들이 자신의 잘못된 가정을 해결하기 위해 몇 시간을 소비해야 한다는 것을 의미하며 시간과 노력을 낭비합니다... 수치스럽습니다.
명령줄에서 매개 변수를 허용하는 형식으로 프로그램이 있는 경우 다음과 같은 Bash 루프를 사용할 수 있습니다.
for (( i=1; i<=20; i++ )); do ./yourprog $i 0.0 10.0 ; done > output.txt
데이터를 공백이나 탭으로 구분된 열에 출력하는 경우 *
또는 열에 데이터가 누락된 경우 데이터를 플롯하는 데 -
사용할 수 있습니다 .gnuplot
예를 들어, 다음 output.txt
과 같은 경우
#N result error
1 3.1 0.04159265359
2 3.14 0.00159265359
3 3.141 0.00059265359
등등, 예를 들어 데이터를 볼 수 있습니다.
gnuplot -p -e 'plot "output.txt" u 2:3 notitle w lines'
Gnuplot은 a로 시작하는 줄을 무시하므로 #
각 열의 용도를 알려주는 파일 시작 부분의 주석이나 헤더에 이를 사용할 수 있습니다. 참조선적 서류 비치자세한 내용은 저는 개인적으로 플롯을 작은 파일로 저장하는 것을 선호 SVG
하지만 PDF
고품질의 벡터 그래픽을 사용합니다. 특히 교과목으로 추천하는 것이 바로 이것이다.
답변2
컴파일하고 링크하는 중이므로 출력은 개체 파일이 아닌 실행 파일이 되어 .o 접미사를 오해하게 만듭니다.
gcc -o err trap_error.c -lm
더 나은 생각일 수도 있습니다.
요청하신 내용이 명확하지 않지만 자동 생성된 입력을 제공하고 모든 출력을 파일로 리디렉션하려는 것 같습니다. N= 2^{i}, i= 1,2 ....20;
다음을 사용하여 bash에서 생성할 수 있습니다 .
for ((i=2;i<2**20;i*=2)); do echo "$i" ; done
-1과 1이 각각 하한과 상한이 될 경우 $i 뒤에 이를 추가하고 각 트리플을 프로그램 호출로 파이프할 수 있습니다.
for ((i=2;i<2**20;i*=2)); do echo "$i -1 1" | ./err ; done > out.txt
이 > out.txt
부분은 모든 ./err 호출의 모든 출력을 out.txt
.