Escrevendo um script shell Unix para chamar uma função C e redirecionando dados para um arquivo .txt

1

Sou novo no script da Shell. Desejo escrever um script Unix que chame um programa em C para N= 2^{i} , i= 1,2 ....20 ; e depois gravar esses dados em um arquivo.

(Este programa calcula a integral definida usando a regra trapezoidal em C e retorna o resultado e erro iterativo para cada termo N.)

Enquanto eu comecei a aprender C, escrevi meu código para a regra trapezoidal:

#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);

}

Eu executo este código por

gcc -o err.o trap_error.c -lm

e minha versão do gcc é gcc (Ubuntu 5.4.0-6ubuntu1~16.04.2) 5.4.0 20160609

Eu pesquisei na Internet aleatoriamente, mas não encontrei informações úteis, acho que também tenho que modificar meu código. Se você apenas me ajudar a escrever o script Unix e depois redirecionar a saída em um arquivo .txt . Um script Unix com linhas explicadas será muito útil.

    
por bhjghjh 22.09.2016 / 19:50

2 respostas

1

Você está compilando e vinculando, de modo que a saída seja executável, não e objeto, o que torna o sufixo .o enganoso.

gcc -o err trap_error.c -lm

pode ser uma ideia melhor.

Não está muito claro o que você está perguntando, mas parece que você está tentando alimentar alguma entrada gerada automaticamente e redirecionar todas as saídas para um arquivo. Você pode gerar N= 2^{i}, i= 1,2 ....20; no bash com:

for ((i=2;i<2**20;i*=2)); do echo "$i" ; done

Se -1 e 1 vão ser o seu limite inferior e superior respectivamente, então você pode adicionar aqueles após $ i, e canalizar cada tripla para uma invocação do seu programa:

for ((i=2;i<2**20;i*=2)); do echo "$i -1 1" | ./err ; done > out.txt

A parte > out.txt redirecionará todas as saídas de todas as invocações ./err para out.txt .

    
por 22.09.2016 / 20:16
4

Em vez de avisar os usuários e ler os parâmetros da entrada padrão, você deve adotar a filosofia Unix e usar comandos parâmetros de linha.

O exemplo a seguir é um pouco longo, porque eu queria mostrar minhas funções de verificação de parâmetros preferenciais. A família de funções scanf() não verifica o estouro, portanto strto*() precisa ser usado. Além disso, ocasionalmente pode haver lixo após o número (digamos, '12l' - sendo a última letra L em vez de '121'), o que eu pessoalmente quero entender.

#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 != '
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;
}
' && isspace(*end)) end++; if (*end != '
#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;
}
') 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 != '
for (( i=1; i<=20; i++ )); do ./yourprog $i 0.0 10.0 ; done > output.txt
' && isspace(*end)) end++; if (*end != '
#N result error
1  3.1   0.04159265359
2  3.14  0.00159265359
3  3.141 0.00059265359
') return errno = EINVAL; if (v) *v = val; return 0; }

Acima, parse_long() suporta a notação decimal ( 987 ), hexadecimal ( 0x3DB ) e octal ( 01733 ).

O main() é então algo como

gnuplot -p -e 'plot "output.txt" u 2:3 notitle w lines'

O setlocale(LC_ALL, ""); diz à biblioteca C para examinar o ambiente atual e configurar a localização para corresponder. Este programa usa somente a classe LC_CTYPE , para determinar quais caracteres são espaços em branco (espaços ou tabulações). No entanto, é uma boa prática entrar em contato: se, em algum momento, você desejar oferecer suporte a caracteres como ä e , poderá alternar para caracteres largos e E / S.

Como aluno, você pode omitir parse_long() e parse_double() e substituí-los nas cláusulas if por sscanf() e ignorar a localização. Isso poupa algumas linhas,

#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 != '
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;
}
' && isspace(*end)) end++; if (*end != '
#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;
}
') 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 != '
for (( i=1; i<=20; i++ )); do ./yourprog $i 0.0 10.0 ; done > output.txt
' && isspace(*end)) end++; if (*end != '
#N result error
1  3.1   0.04159265359
2  3.14  0.00159265359
3  3.141 0.00059265359
') return errno = EINVAL; if (v) *v = val; return 0; }

mas, na minha opinião, por que aprender uma maneira que não é suficiente na prática? Eu pessoalmente conheço casos em que suposições tolas como "Os nomes das pessoas contêm apenas letras de A a Z" levaram dezenas de horas para contornar (um serviço 411 em um cluster de computação com usuários com nomes não ingleses). Vivemos em um mundo global, e vocês, falantes de inglês, entram melhor na fila e deixam de lado suas suposições tolas.

Não é como se as pessoas pudessem aprender a localização depois disso. A maioria dos "programadores C experientes" que eu encontrei parece não saber, nem se importar, sobre problemas de localização ou conjunto de caracteres. (Bem, além de usar UTF-8 em todos os lugares .) Isso significa que outros têm que gastar horas e horas para trabalhar em torno de suas suposições erradas, perdendo tempo e esforço ... Vergonhoso.

Quando você tem seu programa em um formulário que aceita os parâmetros na linha de comando, você pode usar loops Bash como

gnuplot -p -e 'plot "output.txt" u 2:3 notitle w lines'

Observe que, se você enviar dados para espaços ou colunas separadas por tabulação, com algo como * ou - , se uma coluna tiver dados ausentes, você poderá usar gnuplot para plotar os dados.

Por exemplo, se você tiver output.txt com

%pre%

e assim por diante, você pode ver os dados usando, por exemplo,

%pre%

O Gnuplot ignora as linhas que começam com # , então você pode usá-las para comentários ou cabeçalhos no início do arquivo, informando o que cada coluna serve. Consulte a documentação para obter mais informações. Eu pessoalmente prefiro salvar gráficos no formato SVG ou PDF , para que sejam arquivos pequenos, mas com gráficos vetoriais de alta qualidade. Isto é o que eu recomendo para o curso, em particular.

    
por 22.09.2016 / 20:42