Learning I / O. Possibility of showing result of a command and error below

0

Studying redirects and pipelines I can not find an answer for the following situation:

Suppose I enter a command at the prompt, and this one (here I have doubts) can:

  • Show the result of the command.
  • Show an error.

  • But could it show a result and at the same time an error?

  • I do not know, like a command returns a result and an error occurs with something and shows that error ...

    In this case, how could I recreate this (I can not think of any way) and redirect the result of the command to one file and the error to another?

    For the first two cases I have it clear.

    Thanks for your answers.

        
    asked by Minglanillas 08.11.2018 в 16:23
    source

    2 answers

    0

    In Unix you have the convention that a program returns 0 in case of success a positive number in case of warning (> 0) and a negative number in case of error ( stderr (almost mandatory if stdout is the program's own output)

    Suppose you have a program called repeat which repeats a text n times in stdout .

    The program does the following:

    • returns 0 on success
    • shows warnings in case n is odd, suppose performance losses (> 0)
    • error in case n is negative (< 0)

    repeat

    #!/bin/env  bash
    if [ "$#" -ne 2 ]; then
        echo "error: invalid number of arguments" >&2
        exit -1
    fi
    
    if (( $1 < 0)); then
        echo "error: invalid argument \"$1\" is not a positive number" >&2
        exit -1;
    fi
    
    ret=0
    if (( $1 % 2 == 1)); then
        echo "warning: n is odd. Wait this will take some time" >&2
        sleep 5s
        ret=1
    fi
    
    for (( i = 0; i < $1; i++ )) do
        echo $2
    done
    
    exit $ret
    

    Private departures:

    $ ./repetir 4 "Hola mundo"
    Hola mundo
    Hola mundo
    Hola mundo
    Hola mundo
    
    $ ./repetir 5 "Hola mundo"
    warning: n is odd. Wait this will take some time
    Hola mundo
    Hola mundo
    Hola mundo
    Hola mundo
    Hola mundo
    

    Now answering:

      

    ... could it show a result and at the same time an error?

    Yes, as you can see doing ./repetir 5 "hola mundo" shows an error, in this particular case the error is that an odd number of lines is printed and we assume that this exponentially degrades the performance of the application (it takes longer). However this error is recoverable, that is, the application can follow its course and give the correct output, so the application shows a message and at the same time the output of the program.

      

    How could I ... redirect the result of the command to one file and the error to another?

    To get the result, simply redirect stdout to one file and stderr to another

     $ command >salida.txt 2>error.txt
    

    Example:

    $ ./repetir 5 "Hola mundo" >salida.txt 2>error.txt
    
    $ cat salida.txt
    Hola mundo
    Hola mundo
    Hola mundo
    Hola mundo
    Hola mundo
    
    $ cat error.txt
    warning: n is odd. Wait this will take some time
    

    If you want to ignore the errors, just redirect stderr to / dev / null

    $ command 2>/dev/null
    

    Example:

    $ ./repetir 5 "Hola mundo" 2>/dev/null
    Hola mundo
    Hola mundo
    Hola mundo
    Hola mundo
    Hola mundo
    

    Note: This works only if the program follows the conventions that I put at the beginning. In the case of Windows many programs fail and keep returning 0 (success), it is also the case that the errors are in stdout instead of stderr complicating the separation of the output and error messages. In these cases you should use some text tool such as grep, awk, or thirst.

        
    answered by 08.11.2018 / 19:11
    source
    0

    Something that you can also do, although to my consideration it is something "extreme". It is redirecting all terminal errors to a file.

    The terminal is a program, and like every program it has file descriptors to communicate with others.

    You can see the file descriptors that this process has in its information folder in /proc/<pid>/fd

    To know the pid of your terminal you can do this $ echo $$ and it will display the pid of your terminal in progress, let's say something similar happens.

    $ echo $$
    13
    

    Then "13" is the pid of your terminal. Now you execute this:

    $ ls -la /proc/13/fd  # recuerda que esto es sólo un ejemplo de pid.
    total 0
    dr-x------ 2 usuario usuario 0 Oct 10 23:38 .
    dr-xr-xr-x 7 usuario usuario 0 Oct 10 23:38 ..
    lrwx------ 1 usuario usuario 0 Oct 11 23:12 0 -> /dev/tty3  #nota estos descriptores de archivo
    lrwx------ 1 usuario usuario 0 Oct 11 23:10 1 -> /dev/tty3  #este
    lrwx------ 1 usuario usuario 0 Oct 11 23:10 10 -> /dev/tty3
    lr-x------ 1 usuario usuario 0 Oct 11 23:10 12 -> /usr/share/zsh/functions/Completion.zwc
    lrwx------ 1 usuario usuario 0 Oct 11 23:10 2 -> /dev/tty3 # y este. Trabajaremos con este.
    

    This program we ran to make a rollback later. While we have to keep the fact that the fd 2 is a symbolic link to /dev/tty3

    Now I present you exec . It is a built-in bash that replaces the terminal with the command that you put, but it also serves to redirect the file descriptors.

    Remember that the stderr has the file descriptor number 2, so you can apply this.

    $ exec 2> /ruta/archivo/errores.log # y luego puedes correr todas las atrocidades que quieras.
    $ asdf 
    $ cat archivo_inexistente
    $ ls archivo_inexistente
    

    And you will not see the errors in the console, they will all be in the errors.log file that, when using cat to show your co-habit, will throw something of this style.

    $ cat /ruta/de/errores.log
    zsh: command not found: lasdf
    zsh: command not found: asdfasd
    zsh: command not found: edc
    zsh: command not found: edfvrf
    cat: asdfa: No such file or directory
    cat: sd: No such file or directory
    ls: cannot access 'ygvc': No such file or directory
    

    What have been all the errors you've had since you redirected the terminal's stderr.

    To return to normal, just rerun the exec command redirecting the stderr to the file it was linked to, remember that it was /dev/tty3

    $ exec 2> /dev/tty3
    

    And you will see the errors in your terminal from now on.

    Something I did not see mentioned is the & symbol. This is useful in cases of verbose or silent records.

    For example, to redirect both stdout and stderr to a file, this can be done.

    $ comando >archivo 2>&1
    $ comando &> archivo
    

    Both forms are equivalent. And sometimes it can help to just run processes without knowing what goes on inside and knowing only the exit status. For example.

    comando_o_funcion_rara &> /dev/null
    if [[ "$?" == 0 ]] 
    then
        #Código de que el programa anterior salió bien.
    else
        #Código de que el programa anterior salió mal.
    fi
    

    A case with which I recently found myself was when creating a system of reports that consulted a database through a proxy.

    As there were many queries to make, I had a module with many editable queries on the fly, but, as often happens, I made the program very long and complex without testing every change I made until the end. The results of the queries did not come out as expected, so to debug it occurred to me to show the queries through the stderr, since the stdout of each function in each module would be required by another function that would call it, so I could not mix in the code both file descriptors or use the stdout to debug.

    Everything went well, I got the answers (erroneous) of the consultations to the db and their corresponding consultations without interfering, but they were so many queries and so many data that I needed to see them at the same time and slowly. So I "piped" the output to less but only showed me the data and not the queries ... of course, I piped the stdout of the system to less and the queries went to the stderr, so I redirected the stderr to the stdout and then passed it through less .

    $ programa 2>&1 | less
    

    That is, when connecting programs or commands through pipes, they do not connect anymore, but rather their file descriptors communicate with each other, and if you do not specify one, the program on the left redirects your stdout to the stdin of the right, and so on consecutively. And the stderr would never propagate through these.

    Another use that you can give is the following:

    $ comando1 | comando2 2> /dev/null | comando3
    #                       |             |___ Este comando corre bien
    #                       |__________________Este no arroja nada por su stderr así que 
    #                                          no habrá confusiones cuando termine la 
    #                                          ejecución de toda la línea.
    
        
    answered by 12.11.2018 в 07:01