how input redirection works?












2















On my understanding, any command that reads from standard input (i.e keyboard), that it gets its input from a file.



$echo < text_content.txt

$


But echo command does not read and display the text_content.txt on the terminal. what's wrong here?










share|improve this question


















  • 3





    echo does not read from stdin. cat does. Try cat <text_content.txt instead.

    – John1024
    Feb 23 at 7:36
















2















On my understanding, any command that reads from standard input (i.e keyboard), that it gets its input from a file.



$echo < text_content.txt

$


But echo command does not read and display the text_content.txt on the terminal. what's wrong here?










share|improve this question


















  • 3





    echo does not read from stdin. cat does. Try cat <text_content.txt instead.

    – John1024
    Feb 23 at 7:36














2












2








2








On my understanding, any command that reads from standard input (i.e keyboard), that it gets its input from a file.



$echo < text_content.txt

$


But echo command does not read and display the text_content.txt on the terminal. what's wrong here?










share|improve this question














On my understanding, any command that reads from standard input (i.e keyboard), that it gets its input from a file.



$echo < text_content.txt

$


But echo command does not read and display the text_content.txt on the terminal. what's wrong here?







14.04 command-line scripts redirect






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Feb 23 at 7:25









rajini rajarajini raja

235




235








  • 3





    echo does not read from stdin. cat does. Try cat <text_content.txt instead.

    – John1024
    Feb 23 at 7:36














  • 3





    echo does not read from stdin. cat does. Try cat <text_content.txt instead.

    – John1024
    Feb 23 at 7:36








3




3





echo does not read from stdin. cat does. Try cat <text_content.txt instead.

– John1024
Feb 23 at 7:36





echo does not read from stdin. cat does. Try cat <text_content.txt instead.

– John1024
Feb 23 at 7:36










1 Answer
1






active

oldest

votes


















3














stdin and Commands




On my understanding, any command that reads from standard input (i.e keyboard), that it gets its input from a file.




Effectively, yes. As I've discussed in my answer on What characterizes a file in Linux/Unix?, a file is any object on which you can execute standard operations such as read(), open(), write(), close(). stdin being represented via file descriptor 0 is effectively a file in that regard, and any command/process in Linux gets 3 standard file descriptors - stdin,stdout,stderr - when that process is started. What are the actual files behind those file descriptors ? The command doesn't care and shouldn't, as long as it can do operations on it.




But echo command does not read and display the text_content.txt on the terminal. what's wrong here?




Now, command is free to do what it will with those file descriptors1. In case of echo it only deals with stdout and doesn't perform any action on stdin at all. So there's nothing wrong with the command itself.



< redirection will open() the file text_content.txt for reading, and it still will assign file descriptor ( for example 3 ) returned from open() call to file descriptor 0, and if a command is concerned with stdin - it will read from file descriptor 0 as if nothing happened.In fact, you will see that in action, if you run strace -f -e dup2,write,openat bash -c 'echo < text_content.txt



openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3
dup2(3, 0) = 0
write(1, "n", 1
) = 1
dup2(10, 0) = 0
+++ exited with 0 +++


Notice the dup2() system call. That's how file descriptor 3 (the file) is assigned/redirected. In sort of cp original copy syntax, dup2(3,0) makes a copy of file descriptor 3 to file descriptor 0, and they point to same file.



Notice also that write() output a newline to file descriptor 1. That's the default behavior. If we do strace -f -e dup2,write,openat bash -c 'echo FOO < /etc/passwd' here's what we will see



dup2(3, 0)                              = 0
write(1, "FOOn", 4FOO
) = 4
dup2(10, 0) = 0
+++ exited with 0 +++


So again, nothing wrong here - redirections are performed properly and echo does its job of writing stuff to stdout which is file descriptor 1.





How to actually read a file



Now, lets address something else. How can we read a file in shell ? Well, for that there exists cat command, which accepts arguments, so you can do just cat file.txt. Can you do cat < file.txt ? Sure. But that means shell will have to do that dup2() call, whereas cat file.txt doesn't - so there's less unnecessary syscalls is what I'm saying.



In complex cases, such as when you need to perform an action on each line of the file, you would do



while IFS= read -r line || [ -n "$line" ]; do
# command to process line variable here
done < /etc/passwd


Now, for the whole loop file descriptor 0 will be a copy of whatever file descriptor is returned from opening /etc/passwd. Of course, if you can use cat or another specific command to the job of reading a file - do that. Shell is slow method and has a lot of pitfalls. See also, Why is using a shell loop to process text considered bad practice?





1. Some applications still might care about what they can do with stdin or detect if stdin is a file or pipeline. When stdin file descriptor is assigned as read-end of pipeline (which is also a file descriptor) the output is not seekable (meaning that application written in C or another language cannot use seek() syscall to quickly navigate to specific byte offset in a file). A good example of that is given in the question titled What is the difference between “cat file | ./binary” and “./binary < file”?



Sidenote: on Linux it's not exactly keyboard from where stdin gets its input. If you do



$ ls -l /proc/self/fd/0
lrwx------ 1 serg serg 64 Feb 23 16:45 /proc/self/fd/0 -> /dev/pts/0


you will see in the output that it is /dev/pts/0 terminal device to which stdin points initially. The terminal device then interfaces with keyboard, or it could as well be serial cable.



Additionally, if file is not very large, you could take advantage of bash's mapfile builtin to read lines into array:



mapfile  -t  < /etc/passwd
for i in "${MAPFILE[@]}"; do echo "$i"; done







share|improve this answer

























    Your Answer








    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "89"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1120556%2fhow-input-redirection-works%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    1 Answer
    1






    active

    oldest

    votes








    1 Answer
    1






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    3














    stdin and Commands




    On my understanding, any command that reads from standard input (i.e keyboard), that it gets its input from a file.




    Effectively, yes. As I've discussed in my answer on What characterizes a file in Linux/Unix?, a file is any object on which you can execute standard operations such as read(), open(), write(), close(). stdin being represented via file descriptor 0 is effectively a file in that regard, and any command/process in Linux gets 3 standard file descriptors - stdin,stdout,stderr - when that process is started. What are the actual files behind those file descriptors ? The command doesn't care and shouldn't, as long as it can do operations on it.




    But echo command does not read and display the text_content.txt on the terminal. what's wrong here?




    Now, command is free to do what it will with those file descriptors1. In case of echo it only deals with stdout and doesn't perform any action on stdin at all. So there's nothing wrong with the command itself.



    < redirection will open() the file text_content.txt for reading, and it still will assign file descriptor ( for example 3 ) returned from open() call to file descriptor 0, and if a command is concerned with stdin - it will read from file descriptor 0 as if nothing happened.In fact, you will see that in action, if you run strace -f -e dup2,write,openat bash -c 'echo < text_content.txt



    openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3
    dup2(3, 0) = 0
    write(1, "n", 1
    ) = 1
    dup2(10, 0) = 0
    +++ exited with 0 +++


    Notice the dup2() system call. That's how file descriptor 3 (the file) is assigned/redirected. In sort of cp original copy syntax, dup2(3,0) makes a copy of file descriptor 3 to file descriptor 0, and they point to same file.



    Notice also that write() output a newline to file descriptor 1. That's the default behavior. If we do strace -f -e dup2,write,openat bash -c 'echo FOO < /etc/passwd' here's what we will see



    dup2(3, 0)                              = 0
    write(1, "FOOn", 4FOO
    ) = 4
    dup2(10, 0) = 0
    +++ exited with 0 +++


    So again, nothing wrong here - redirections are performed properly and echo does its job of writing stuff to stdout which is file descriptor 1.





    How to actually read a file



    Now, lets address something else. How can we read a file in shell ? Well, for that there exists cat command, which accepts arguments, so you can do just cat file.txt. Can you do cat < file.txt ? Sure. But that means shell will have to do that dup2() call, whereas cat file.txt doesn't - so there's less unnecessary syscalls is what I'm saying.



    In complex cases, such as when you need to perform an action on each line of the file, you would do



    while IFS= read -r line || [ -n "$line" ]; do
    # command to process line variable here
    done < /etc/passwd


    Now, for the whole loop file descriptor 0 will be a copy of whatever file descriptor is returned from opening /etc/passwd. Of course, if you can use cat or another specific command to the job of reading a file - do that. Shell is slow method and has a lot of pitfalls. See also, Why is using a shell loop to process text considered bad practice?





    1. Some applications still might care about what they can do with stdin or detect if stdin is a file or pipeline. When stdin file descriptor is assigned as read-end of pipeline (which is also a file descriptor) the output is not seekable (meaning that application written in C or another language cannot use seek() syscall to quickly navigate to specific byte offset in a file). A good example of that is given in the question titled What is the difference between “cat file | ./binary” and “./binary < file”?



    Sidenote: on Linux it's not exactly keyboard from where stdin gets its input. If you do



    $ ls -l /proc/self/fd/0
    lrwx------ 1 serg serg 64 Feb 23 16:45 /proc/self/fd/0 -> /dev/pts/0


    you will see in the output that it is /dev/pts/0 terminal device to which stdin points initially. The terminal device then interfaces with keyboard, or it could as well be serial cable.



    Additionally, if file is not very large, you could take advantage of bash's mapfile builtin to read lines into array:



    mapfile  -t  < /etc/passwd
    for i in "${MAPFILE[@]}"; do echo "$i"; done







    share|improve this answer






























      3














      stdin and Commands




      On my understanding, any command that reads from standard input (i.e keyboard), that it gets its input from a file.




      Effectively, yes. As I've discussed in my answer on What characterizes a file in Linux/Unix?, a file is any object on which you can execute standard operations such as read(), open(), write(), close(). stdin being represented via file descriptor 0 is effectively a file in that regard, and any command/process in Linux gets 3 standard file descriptors - stdin,stdout,stderr - when that process is started. What are the actual files behind those file descriptors ? The command doesn't care and shouldn't, as long as it can do operations on it.




      But echo command does not read and display the text_content.txt on the terminal. what's wrong here?




      Now, command is free to do what it will with those file descriptors1. In case of echo it only deals with stdout and doesn't perform any action on stdin at all. So there's nothing wrong with the command itself.



      < redirection will open() the file text_content.txt for reading, and it still will assign file descriptor ( for example 3 ) returned from open() call to file descriptor 0, and if a command is concerned with stdin - it will read from file descriptor 0 as if nothing happened.In fact, you will see that in action, if you run strace -f -e dup2,write,openat bash -c 'echo < text_content.txt



      openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3
      dup2(3, 0) = 0
      write(1, "n", 1
      ) = 1
      dup2(10, 0) = 0
      +++ exited with 0 +++


      Notice the dup2() system call. That's how file descriptor 3 (the file) is assigned/redirected. In sort of cp original copy syntax, dup2(3,0) makes a copy of file descriptor 3 to file descriptor 0, and they point to same file.



      Notice also that write() output a newline to file descriptor 1. That's the default behavior. If we do strace -f -e dup2,write,openat bash -c 'echo FOO < /etc/passwd' here's what we will see



      dup2(3, 0)                              = 0
      write(1, "FOOn", 4FOO
      ) = 4
      dup2(10, 0) = 0
      +++ exited with 0 +++


      So again, nothing wrong here - redirections are performed properly and echo does its job of writing stuff to stdout which is file descriptor 1.





      How to actually read a file



      Now, lets address something else. How can we read a file in shell ? Well, for that there exists cat command, which accepts arguments, so you can do just cat file.txt. Can you do cat < file.txt ? Sure. But that means shell will have to do that dup2() call, whereas cat file.txt doesn't - so there's less unnecessary syscalls is what I'm saying.



      In complex cases, such as when you need to perform an action on each line of the file, you would do



      while IFS= read -r line || [ -n "$line" ]; do
      # command to process line variable here
      done < /etc/passwd


      Now, for the whole loop file descriptor 0 will be a copy of whatever file descriptor is returned from opening /etc/passwd. Of course, if you can use cat or another specific command to the job of reading a file - do that. Shell is slow method and has a lot of pitfalls. See also, Why is using a shell loop to process text considered bad practice?





      1. Some applications still might care about what they can do with stdin or detect if stdin is a file or pipeline. When stdin file descriptor is assigned as read-end of pipeline (which is also a file descriptor) the output is not seekable (meaning that application written in C or another language cannot use seek() syscall to quickly navigate to specific byte offset in a file). A good example of that is given in the question titled What is the difference between “cat file | ./binary” and “./binary < file”?



      Sidenote: on Linux it's not exactly keyboard from where stdin gets its input. If you do



      $ ls -l /proc/self/fd/0
      lrwx------ 1 serg serg 64 Feb 23 16:45 /proc/self/fd/0 -> /dev/pts/0


      you will see in the output that it is /dev/pts/0 terminal device to which stdin points initially. The terminal device then interfaces with keyboard, or it could as well be serial cable.



      Additionally, if file is not very large, you could take advantage of bash's mapfile builtin to read lines into array:



      mapfile  -t  < /etc/passwd
      for i in "${MAPFILE[@]}"; do echo "$i"; done







      share|improve this answer




























        3












        3








        3







        stdin and Commands




        On my understanding, any command that reads from standard input (i.e keyboard), that it gets its input from a file.




        Effectively, yes. As I've discussed in my answer on What characterizes a file in Linux/Unix?, a file is any object on which you can execute standard operations such as read(), open(), write(), close(). stdin being represented via file descriptor 0 is effectively a file in that regard, and any command/process in Linux gets 3 standard file descriptors - stdin,stdout,stderr - when that process is started. What are the actual files behind those file descriptors ? The command doesn't care and shouldn't, as long as it can do operations on it.




        But echo command does not read and display the text_content.txt on the terminal. what's wrong here?




        Now, command is free to do what it will with those file descriptors1. In case of echo it only deals with stdout and doesn't perform any action on stdin at all. So there's nothing wrong with the command itself.



        < redirection will open() the file text_content.txt for reading, and it still will assign file descriptor ( for example 3 ) returned from open() call to file descriptor 0, and if a command is concerned with stdin - it will read from file descriptor 0 as if nothing happened.In fact, you will see that in action, if you run strace -f -e dup2,write,openat bash -c 'echo < text_content.txt



        openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3
        dup2(3, 0) = 0
        write(1, "n", 1
        ) = 1
        dup2(10, 0) = 0
        +++ exited with 0 +++


        Notice the dup2() system call. That's how file descriptor 3 (the file) is assigned/redirected. In sort of cp original copy syntax, dup2(3,0) makes a copy of file descriptor 3 to file descriptor 0, and they point to same file.



        Notice also that write() output a newline to file descriptor 1. That's the default behavior. If we do strace -f -e dup2,write,openat bash -c 'echo FOO < /etc/passwd' here's what we will see



        dup2(3, 0)                              = 0
        write(1, "FOOn", 4FOO
        ) = 4
        dup2(10, 0) = 0
        +++ exited with 0 +++


        So again, nothing wrong here - redirections are performed properly and echo does its job of writing stuff to stdout which is file descriptor 1.





        How to actually read a file



        Now, lets address something else. How can we read a file in shell ? Well, for that there exists cat command, which accepts arguments, so you can do just cat file.txt. Can you do cat < file.txt ? Sure. But that means shell will have to do that dup2() call, whereas cat file.txt doesn't - so there's less unnecessary syscalls is what I'm saying.



        In complex cases, such as when you need to perform an action on each line of the file, you would do



        while IFS= read -r line || [ -n "$line" ]; do
        # command to process line variable here
        done < /etc/passwd


        Now, for the whole loop file descriptor 0 will be a copy of whatever file descriptor is returned from opening /etc/passwd. Of course, if you can use cat or another specific command to the job of reading a file - do that. Shell is slow method and has a lot of pitfalls. See also, Why is using a shell loop to process text considered bad practice?





        1. Some applications still might care about what they can do with stdin or detect if stdin is a file or pipeline. When stdin file descriptor is assigned as read-end of pipeline (which is also a file descriptor) the output is not seekable (meaning that application written in C or another language cannot use seek() syscall to quickly navigate to specific byte offset in a file). A good example of that is given in the question titled What is the difference between “cat file | ./binary” and “./binary < file”?



        Sidenote: on Linux it's not exactly keyboard from where stdin gets its input. If you do



        $ ls -l /proc/self/fd/0
        lrwx------ 1 serg serg 64 Feb 23 16:45 /proc/self/fd/0 -> /dev/pts/0


        you will see in the output that it is /dev/pts/0 terminal device to which stdin points initially. The terminal device then interfaces with keyboard, or it could as well be serial cable.



        Additionally, if file is not very large, you could take advantage of bash's mapfile builtin to read lines into array:



        mapfile  -t  < /etc/passwd
        for i in "${MAPFILE[@]}"; do echo "$i"; done







        share|improve this answer















        stdin and Commands




        On my understanding, any command that reads from standard input (i.e keyboard), that it gets its input from a file.




        Effectively, yes. As I've discussed in my answer on What characterizes a file in Linux/Unix?, a file is any object on which you can execute standard operations such as read(), open(), write(), close(). stdin being represented via file descriptor 0 is effectively a file in that regard, and any command/process in Linux gets 3 standard file descriptors - stdin,stdout,stderr - when that process is started. What are the actual files behind those file descriptors ? The command doesn't care and shouldn't, as long as it can do operations on it.




        But echo command does not read and display the text_content.txt on the terminal. what's wrong here?




        Now, command is free to do what it will with those file descriptors1. In case of echo it only deals with stdout and doesn't perform any action on stdin at all. So there's nothing wrong with the command itself.



        < redirection will open() the file text_content.txt for reading, and it still will assign file descriptor ( for example 3 ) returned from open() call to file descriptor 0, and if a command is concerned with stdin - it will read from file descriptor 0 as if nothing happened.In fact, you will see that in action, if you run strace -f -e dup2,write,openat bash -c 'echo < text_content.txt



        openat(AT_FDCWD, "/etc/passwd", O_RDONLY) = 3
        dup2(3, 0) = 0
        write(1, "n", 1
        ) = 1
        dup2(10, 0) = 0
        +++ exited with 0 +++


        Notice the dup2() system call. That's how file descriptor 3 (the file) is assigned/redirected. In sort of cp original copy syntax, dup2(3,0) makes a copy of file descriptor 3 to file descriptor 0, and they point to same file.



        Notice also that write() output a newline to file descriptor 1. That's the default behavior. If we do strace -f -e dup2,write,openat bash -c 'echo FOO < /etc/passwd' here's what we will see



        dup2(3, 0)                              = 0
        write(1, "FOOn", 4FOO
        ) = 4
        dup2(10, 0) = 0
        +++ exited with 0 +++


        So again, nothing wrong here - redirections are performed properly and echo does its job of writing stuff to stdout which is file descriptor 1.





        How to actually read a file



        Now, lets address something else. How can we read a file in shell ? Well, for that there exists cat command, which accepts arguments, so you can do just cat file.txt. Can you do cat < file.txt ? Sure. But that means shell will have to do that dup2() call, whereas cat file.txt doesn't - so there's less unnecessary syscalls is what I'm saying.



        In complex cases, such as when you need to perform an action on each line of the file, you would do



        while IFS= read -r line || [ -n "$line" ]; do
        # command to process line variable here
        done < /etc/passwd


        Now, for the whole loop file descriptor 0 will be a copy of whatever file descriptor is returned from opening /etc/passwd. Of course, if you can use cat or another specific command to the job of reading a file - do that. Shell is slow method and has a lot of pitfalls. See also, Why is using a shell loop to process text considered bad practice?





        1. Some applications still might care about what they can do with stdin or detect if stdin is a file or pipeline. When stdin file descriptor is assigned as read-end of pipeline (which is also a file descriptor) the output is not seekable (meaning that application written in C or another language cannot use seek() syscall to quickly navigate to specific byte offset in a file). A good example of that is given in the question titled What is the difference between “cat file | ./binary” and “./binary < file”?



        Sidenote: on Linux it's not exactly keyboard from where stdin gets its input. If you do



        $ ls -l /proc/self/fd/0
        lrwx------ 1 serg serg 64 Feb 23 16:45 /proc/self/fd/0 -> /dev/pts/0


        you will see in the output that it is /dev/pts/0 terminal device to which stdin points initially. The terminal device then interfaces with keyboard, or it could as well be serial cable.



        Additionally, if file is not very large, you could take advantage of bash's mapfile builtin to read lines into array:



        mapfile  -t  < /etc/passwd
        for i in "${MAPFILE[@]}"; do echo "$i"; done








        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Feb 23 at 9:24

























        answered Feb 23 at 8:13









        Sergiy KolodyazhnyySergiy Kolodyazhnyy

        73.4k9153318




        73.4k9153318






























            draft saved

            draft discarded




















































            Thanks for contributing an answer to Ask Ubuntu!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1120556%2fhow-input-redirection-works%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            Popular posts from this blog

            How to change which sound is reproduced for terminal bell?

            Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents

            Can I use Tabulator js library in my java Spring + Thymeleaf project?