C関数を呼び出してデータを.txtファイルにリダイレクトするUnixシェルスクリプトの作成

C関数を呼び出してデータを.txtファイルにリダイレクトするUnixシェルスクリプトの作成

私はシェルスクリプトに初めて触れました。私は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

ユーザーにメッセージを表示し、標準入力から引数を読むのではなく受け入れる必要があります。Unixの哲学代わりにコマンドラインパラメータを使用してください。

以下の例は、私が好むパラメータチェック機能を示したかったので少し長くなります。scanf()関数系列はオーバーフローを確認しないため、strto*()使用する必要があります。また、時には数字の後にジャンクがあるかもしれません(たとえば、「12l」 - 最後の文字は「121」ではなく文字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()を省略して置き換えることができ、ローカライズを無視できます。数行のコードを節約できます。ifsscanf()

#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はで始まる行を無視するので、#ファイルの先頭にこれらのコメントまたはヘッダーを使用して各列の目的を説明できます。より文書より多くの情報を知りたいです。私は個人的に画像を小さなファイルとして保存したり、高品質のベクトルグラフィックを持つことができる形式でSVG保存したいと思います。PDF私が特におすすめの講座です。

おすすめ記事