Bash: Succinct way to loop over lines from stdin or command line arguments?

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP











up vote
1
down vote

favorite












I've got a bash script I'd like to loop over the lines in stdin, or loop over each argument passed in.



Is there a clean way to write this so I don't have to have 2 loops?



#!/bin/bash

# if we have command line args...
if [ -t 0 ]
then
# loop over arguments
for arg in "$@"
do
# process each argument
done
else
# loop over lines from stdin
while IFS= read -r line; do
# process each line
done
fi


EDIT: I'm looking for a generic solution that just uses a single loop, as I find I want to do this quite often, but have always wrote out 2 loops and then called a function instead. So maybe something that turns stdin into an array, so I could use a single loop instead?







share|improve this question


















  • 1




    What are you actually trying to accomplish ? Sounds like a typical XY question...
    – don_crissti
    Mar 23 at 13:51











  • What's the problem you're trying to solve? What kind of processing needs to happen in the loop?
    – Kusalananda
    Mar 23 at 14:15










  • thanks for the feedback! I write lots of little bash scripts that I like to be able to accepts args from the command line, or from stdin. The particular script i'm writing now is one that will concatenate arguments using a delimiter, so I can write both cat /tmp/it | concat and concat a b c and it'd join these arguments together in both cases, trimming each arg and putting a comma between items. e.g. a,b,c.
    – Brad Parks
    Mar 23 at 14:18















up vote
1
down vote

favorite












I've got a bash script I'd like to loop over the lines in stdin, or loop over each argument passed in.



Is there a clean way to write this so I don't have to have 2 loops?



#!/bin/bash

# if we have command line args...
if [ -t 0 ]
then
# loop over arguments
for arg in "$@"
do
# process each argument
done
else
# loop over lines from stdin
while IFS= read -r line; do
# process each line
done
fi


EDIT: I'm looking for a generic solution that just uses a single loop, as I find I want to do this quite often, but have always wrote out 2 loops and then called a function instead. So maybe something that turns stdin into an array, so I could use a single loop instead?







share|improve this question


















  • 1




    What are you actually trying to accomplish ? Sounds like a typical XY question...
    – don_crissti
    Mar 23 at 13:51











  • What's the problem you're trying to solve? What kind of processing needs to happen in the loop?
    – Kusalananda
    Mar 23 at 14:15










  • thanks for the feedback! I write lots of little bash scripts that I like to be able to accepts args from the command line, or from stdin. The particular script i'm writing now is one that will concatenate arguments using a delimiter, so I can write both cat /tmp/it | concat and concat a b c and it'd join these arguments together in both cases, trimming each arg and putting a comma between items. e.g. a,b,c.
    – Brad Parks
    Mar 23 at 14:18













up vote
1
down vote

favorite









up vote
1
down vote

favorite











I've got a bash script I'd like to loop over the lines in stdin, or loop over each argument passed in.



Is there a clean way to write this so I don't have to have 2 loops?



#!/bin/bash

# if we have command line args...
if [ -t 0 ]
then
# loop over arguments
for arg in "$@"
do
# process each argument
done
else
# loop over lines from stdin
while IFS= read -r line; do
# process each line
done
fi


EDIT: I'm looking for a generic solution that just uses a single loop, as I find I want to do this quite often, but have always wrote out 2 loops and then called a function instead. So maybe something that turns stdin into an array, so I could use a single loop instead?







share|improve this question














I've got a bash script I'd like to loop over the lines in stdin, or loop over each argument passed in.



Is there a clean way to write this so I don't have to have 2 loops?



#!/bin/bash

# if we have command line args...
if [ -t 0 ]
then
# loop over arguments
for arg in "$@"
do
# process each argument
done
else
# loop over lines from stdin
while IFS= read -r line; do
# process each line
done
fi


EDIT: I'm looking for a generic solution that just uses a single loop, as I find I want to do this quite often, but have always wrote out 2 loops and then called a function instead. So maybe something that turns stdin into an array, so I could use a single loop instead?









share|improve this question













share|improve this question




share|improve this question








edited Mar 23 at 14:37

























asked Mar 23 at 13:35









Brad Parks

400321




400321







  • 1




    What are you actually trying to accomplish ? Sounds like a typical XY question...
    – don_crissti
    Mar 23 at 13:51











  • What's the problem you're trying to solve? What kind of processing needs to happen in the loop?
    – Kusalananda
    Mar 23 at 14:15










  • thanks for the feedback! I write lots of little bash scripts that I like to be able to accepts args from the command line, or from stdin. The particular script i'm writing now is one that will concatenate arguments using a delimiter, so I can write both cat /tmp/it | concat and concat a b c and it'd join these arguments together in both cases, trimming each arg and putting a comma between items. e.g. a,b,c.
    – Brad Parks
    Mar 23 at 14:18













  • 1




    What are you actually trying to accomplish ? Sounds like a typical XY question...
    – don_crissti
    Mar 23 at 13:51











  • What's the problem you're trying to solve? What kind of processing needs to happen in the loop?
    – Kusalananda
    Mar 23 at 14:15










  • thanks for the feedback! I write lots of little bash scripts that I like to be able to accepts args from the command line, or from stdin. The particular script i'm writing now is one that will concatenate arguments using a delimiter, so I can write both cat /tmp/it | concat and concat a b c and it'd join these arguments together in both cases, trimming each arg and putting a comma between items. e.g. a,b,c.
    – Brad Parks
    Mar 23 at 14:18








1




1




What are you actually trying to accomplish ? Sounds like a typical XY question...
– don_crissti
Mar 23 at 13:51





What are you actually trying to accomplish ? Sounds like a typical XY question...
– don_crissti
Mar 23 at 13:51













What's the problem you're trying to solve? What kind of processing needs to happen in the loop?
– Kusalananda
Mar 23 at 14:15




What's the problem you're trying to solve? What kind of processing needs to happen in the loop?
– Kusalananda
Mar 23 at 14:15












thanks for the feedback! I write lots of little bash scripts that I like to be able to accepts args from the command line, or from stdin. The particular script i'm writing now is one that will concatenate arguments using a delimiter, so I can write both cat /tmp/it | concat and concat a b c and it'd join these arguments together in both cases, trimming each arg and putting a comma between items. e.g. a,b,c.
– Brad Parks
Mar 23 at 14:18





thanks for the feedback! I write lots of little bash scripts that I like to be able to accepts args from the command line, or from stdin. The particular script i'm writing now is one that will concatenate arguments using a delimiter, so I can write both cat /tmp/it | concat and concat a b c and it'd join these arguments together in both cases, trimming each arg and putting a comma between items. e.g. a,b,c.
– Brad Parks
Mar 23 at 14:18











2 Answers
2






active

oldest

votes

















up vote
2
down vote



accepted










Create data for your while read loop:



#!/bin/sh

if [ "$#" -gt 0 ]; then
# We have command line arguments.
# Output them with newlines in-between.
printf '%sn' "$@"
else
# No command line arguments.
# Just pass stdin on.
cat
fi |
while IFS= read -r; do
printf 'Got "%s"n' "$REPLY"
done


Note that your concat example can be done with the while read loop replaced by tr 'n' ',' or similar.



Also, the -t test says nothing about whether you have command line arguments or not.




Alternatively, to process both command line arguments and standard input (in that order):



#!/bin/sh


if [ "$#" -gt 0 ]; then
# We have command line arguments.
# Output them with newlines in-between.
printf '%sn' "$@"
fi

if [ ! -t 0 ]; then
# Pass stdin on.
cat
fi
|
while IFS= read -r; do
printf 'Got "%s"n' "$REPLY"
done


Or, using short-cut notation that some people seems to like:



#!/bin/sh


[ "$#" -gt 0 ] && printf '%sn' "$@"
[ ! -t 0 ] && cat
|
while IFS= read -r; do
printf 'Got "%s"n' "$REPLY"
done





share|improve this answer






















  • Note that that changes the behaviour if there are arguments that contain newline characters.
    – Stéphane Chazelas
    Mar 23 at 15:04










  • @StéphaneChazelas Yes, command line arguments with literal newlines in them will be broken up into multiple items when they arrive at the loop.
    – Kusalananda
    Mar 23 at 15:07

















up vote
1
down vote













With bash specifically, you could do:



if [ -t 0 ]; then
args=("$@")
else
readarray -t args
fi
for i in "$args[@]"; do
...
done





share|improve this answer




















    Your Answer







    StackExchange.ready(function()
    var channelOptions =
    tags: "".split(" "),
    id: "106"
    ;
    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',
    convertImagesToLinks: false,
    noModals: false,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: null,
    bindNavPrevention: true,
    postfix: "",
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    );



    );








     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f433066%2fbash-succinct-way-to-loop-over-lines-from-stdin-or-command-line-arguments%23new-answer', 'question_page');

    );

    Post as a guest






























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    2
    down vote



    accepted










    Create data for your while read loop:



    #!/bin/sh

    if [ "$#" -gt 0 ]; then
    # We have command line arguments.
    # Output them with newlines in-between.
    printf '%sn' "$@"
    else
    # No command line arguments.
    # Just pass stdin on.
    cat
    fi |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done


    Note that your concat example can be done with the while read loop replaced by tr 'n' ',' or similar.



    Also, the -t test says nothing about whether you have command line arguments or not.




    Alternatively, to process both command line arguments and standard input (in that order):



    #!/bin/sh


    if [ "$#" -gt 0 ]; then
    # We have command line arguments.
    # Output them with newlines in-between.
    printf '%sn' "$@"
    fi

    if [ ! -t 0 ]; then
    # Pass stdin on.
    cat
    fi
    |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done


    Or, using short-cut notation that some people seems to like:



    #!/bin/sh


    [ "$#" -gt 0 ] && printf '%sn' "$@"
    [ ! -t 0 ] && cat
    |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done





    share|improve this answer






















    • Note that that changes the behaviour if there are arguments that contain newline characters.
      – Stéphane Chazelas
      Mar 23 at 15:04










    • @StéphaneChazelas Yes, command line arguments with literal newlines in them will be broken up into multiple items when they arrive at the loop.
      – Kusalananda
      Mar 23 at 15:07














    up vote
    2
    down vote



    accepted










    Create data for your while read loop:



    #!/bin/sh

    if [ "$#" -gt 0 ]; then
    # We have command line arguments.
    # Output them with newlines in-between.
    printf '%sn' "$@"
    else
    # No command line arguments.
    # Just pass stdin on.
    cat
    fi |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done


    Note that your concat example can be done with the while read loop replaced by tr 'n' ',' or similar.



    Also, the -t test says nothing about whether you have command line arguments or not.




    Alternatively, to process both command line arguments and standard input (in that order):



    #!/bin/sh


    if [ "$#" -gt 0 ]; then
    # We have command line arguments.
    # Output them with newlines in-between.
    printf '%sn' "$@"
    fi

    if [ ! -t 0 ]; then
    # Pass stdin on.
    cat
    fi
    |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done


    Or, using short-cut notation that some people seems to like:



    #!/bin/sh


    [ "$#" -gt 0 ] && printf '%sn' "$@"
    [ ! -t 0 ] && cat
    |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done





    share|improve this answer






















    • Note that that changes the behaviour if there are arguments that contain newline characters.
      – Stéphane Chazelas
      Mar 23 at 15:04










    • @StéphaneChazelas Yes, command line arguments with literal newlines in them will be broken up into multiple items when they arrive at the loop.
      – Kusalananda
      Mar 23 at 15:07












    up vote
    2
    down vote



    accepted







    up vote
    2
    down vote



    accepted






    Create data for your while read loop:



    #!/bin/sh

    if [ "$#" -gt 0 ]; then
    # We have command line arguments.
    # Output them with newlines in-between.
    printf '%sn' "$@"
    else
    # No command line arguments.
    # Just pass stdin on.
    cat
    fi |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done


    Note that your concat example can be done with the while read loop replaced by tr 'n' ',' or similar.



    Also, the -t test says nothing about whether you have command line arguments or not.




    Alternatively, to process both command line arguments and standard input (in that order):



    #!/bin/sh


    if [ "$#" -gt 0 ]; then
    # We have command line arguments.
    # Output them with newlines in-between.
    printf '%sn' "$@"
    fi

    if [ ! -t 0 ]; then
    # Pass stdin on.
    cat
    fi
    |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done


    Or, using short-cut notation that some people seems to like:



    #!/bin/sh


    [ "$#" -gt 0 ] && printf '%sn' "$@"
    [ ! -t 0 ] && cat
    |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done





    share|improve this answer














    Create data for your while read loop:



    #!/bin/sh

    if [ "$#" -gt 0 ]; then
    # We have command line arguments.
    # Output them with newlines in-between.
    printf '%sn' "$@"
    else
    # No command line arguments.
    # Just pass stdin on.
    cat
    fi |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done


    Note that your concat example can be done with the while read loop replaced by tr 'n' ',' or similar.



    Also, the -t test says nothing about whether you have command line arguments or not.




    Alternatively, to process both command line arguments and standard input (in that order):



    #!/bin/sh


    if [ "$#" -gt 0 ]; then
    # We have command line arguments.
    # Output them with newlines in-between.
    printf '%sn' "$@"
    fi

    if [ ! -t 0 ]; then
    # Pass stdin on.
    cat
    fi
    |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done


    Or, using short-cut notation that some people seems to like:



    #!/bin/sh


    [ "$#" -gt 0 ] && printf '%sn' "$@"
    [ ! -t 0 ] && cat
    |
    while IFS= read -r; do
    printf 'Got "%s"n' "$REPLY"
    done






    share|improve this answer














    share|improve this answer



    share|improve this answer








    edited Mar 23 at 15:25

























    answered Mar 23 at 15:01









    Kusalananda

    102k13201317




    102k13201317











    • Note that that changes the behaviour if there are arguments that contain newline characters.
      – Stéphane Chazelas
      Mar 23 at 15:04










    • @StéphaneChazelas Yes, command line arguments with literal newlines in them will be broken up into multiple items when they arrive at the loop.
      – Kusalananda
      Mar 23 at 15:07
















    • Note that that changes the behaviour if there are arguments that contain newline characters.
      – Stéphane Chazelas
      Mar 23 at 15:04










    • @StéphaneChazelas Yes, command line arguments with literal newlines in them will be broken up into multiple items when they arrive at the loop.
      – Kusalananda
      Mar 23 at 15:07















    Note that that changes the behaviour if there are arguments that contain newline characters.
    – Stéphane Chazelas
    Mar 23 at 15:04




    Note that that changes the behaviour if there are arguments that contain newline characters.
    – Stéphane Chazelas
    Mar 23 at 15:04












    @StéphaneChazelas Yes, command line arguments with literal newlines in them will be broken up into multiple items when they arrive at the loop.
    – Kusalananda
    Mar 23 at 15:07




    @StéphaneChazelas Yes, command line arguments with literal newlines in them will be broken up into multiple items when they arrive at the loop.
    – Kusalananda
    Mar 23 at 15:07












    up vote
    1
    down vote













    With bash specifically, you could do:



    if [ -t 0 ]; then
    args=("$@")
    else
    readarray -t args
    fi
    for i in "$args[@]"; do
    ...
    done





    share|improve this answer
























      up vote
      1
      down vote













      With bash specifically, you could do:



      if [ -t 0 ]; then
      args=("$@")
      else
      readarray -t args
      fi
      for i in "$args[@]"; do
      ...
      done





      share|improve this answer






















        up vote
        1
        down vote










        up vote
        1
        down vote









        With bash specifically, you could do:



        if [ -t 0 ]; then
        args=("$@")
        else
        readarray -t args
        fi
        for i in "$args[@]"; do
        ...
        done





        share|improve this answer












        With bash specifically, you could do:



        if [ -t 0 ]; then
        args=("$@")
        else
        readarray -t args
        fi
        for i in "$args[@]"; do
        ...
        done






        share|improve this answer












        share|improve this answer



        share|improve this answer










        answered Mar 23 at 15:06









        Stéphane Chazelas

        280k53514846




        280k53514846






















             

            draft saved


            draft discarded


























             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f433066%2fbash-succinct-way-to-loop-over-lines-from-stdin-or-command-line-arguments%23new-answer', 'question_page');

            );

            Post as a guest













































































            Popular posts from this blog

            How to check contact read email or not when send email to Individual?

            Displaying single band from multi-band raster using QGIS

            How many registers does an x86_64 CPU actually have?