Build a command dynamically

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











up vote
8
down vote

favorite
1












I'm working on a script and I need to build the tar command dynamically.



Here are two examples to illustrate what I'm trying to do :



#!/bin/bash

TAR_ME="/tmp"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
_tar="tar "`printf -- '--exclude="%s" ' "$EXCLUDE[@]"`" -zcf tmp.tar.gz"
echo COMMAND: "$_tar"
$_tar "$TAR_ME"

echo -e "nnNEXT:nn"

EXCLUDE=("--exclude=/tmp/hello hello" "--exclude=/tmp/systemd*" "--exclude=/tmp/Temp*")
_tar="tar "`printf -- '%s ' "$EXCLUDE[@]"`" -zcf test.tar.gz"
echo COMMAND: "$_tar"
$_tar "$TAR_ME"


I want to be able to use _tar as a command, I've been able to make it work with classic path, but I need it to work with spaces in folders' name.
And every single time I got errors that look like :



COMMAND: tar --exclude="/tmp/hello hello" --exclude="/tmp/systemd*" --exclude="/tmp/Temp*" -zcf tmp.tar.gz /tmp
tar: hello": Cannot stat: No such file or directory

COMMAND: tar --exclude=/tmp/hello hello --exclude=/tmp/systemd* --exclude=/tmp/Temp* -zcf test.tar.gz
tar: hello: Cannot stat: No such file or directory


Just one thing you need to know, I need my script to work on very old machines, meaning I can't use last bash features.










share|improve this question









New contributor




ShellCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • I believe the --exclude option can only accept a single string after it. You can have multiple --exclude statements though. Maybe try "--exclude=/tmp/hello --exclude=hello" Oops. Nevermind. I misunderstood.
    – Lewis M
    Oct 4 at 13:43











  • @LewisM I think OP want to exclude directory "/tmp/hello hello" (yes, with a space.
    – Archemar
    Oct 4 at 13:44










  • @ShellCode what about quoting all exclude, e.g. "--exclude=/tmp/hello hello"
    – Archemar
    Oct 4 at 13:45










  • Yeah. That's why I put the Oops statement later. :)
    – Lewis M
    Oct 4 at 13:46










  • How about putting eval in front of the execution?
    – jimmij
    Oct 4 at 13:52














up vote
8
down vote

favorite
1












I'm working on a script and I need to build the tar command dynamically.



Here are two examples to illustrate what I'm trying to do :



#!/bin/bash

TAR_ME="/tmp"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
_tar="tar "`printf -- '--exclude="%s" ' "$EXCLUDE[@]"`" -zcf tmp.tar.gz"
echo COMMAND: "$_tar"
$_tar "$TAR_ME"

echo -e "nnNEXT:nn"

EXCLUDE=("--exclude=/tmp/hello hello" "--exclude=/tmp/systemd*" "--exclude=/tmp/Temp*")
_tar="tar "`printf -- '%s ' "$EXCLUDE[@]"`" -zcf test.tar.gz"
echo COMMAND: "$_tar"
$_tar "$TAR_ME"


I want to be able to use _tar as a command, I've been able to make it work with classic path, but I need it to work with spaces in folders' name.
And every single time I got errors that look like :



COMMAND: tar --exclude="/tmp/hello hello" --exclude="/tmp/systemd*" --exclude="/tmp/Temp*" -zcf tmp.tar.gz /tmp
tar: hello": Cannot stat: No such file or directory

COMMAND: tar --exclude=/tmp/hello hello --exclude=/tmp/systemd* --exclude=/tmp/Temp* -zcf test.tar.gz
tar: hello: Cannot stat: No such file or directory


Just one thing you need to know, I need my script to work on very old machines, meaning I can't use last bash features.










share|improve this question









New contributor




ShellCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.



















  • I believe the --exclude option can only accept a single string after it. You can have multiple --exclude statements though. Maybe try "--exclude=/tmp/hello --exclude=hello" Oops. Nevermind. I misunderstood.
    – Lewis M
    Oct 4 at 13:43











  • @LewisM I think OP want to exclude directory "/tmp/hello hello" (yes, with a space.
    – Archemar
    Oct 4 at 13:44










  • @ShellCode what about quoting all exclude, e.g. "--exclude=/tmp/hello hello"
    – Archemar
    Oct 4 at 13:45










  • Yeah. That's why I put the Oops statement later. :)
    – Lewis M
    Oct 4 at 13:46










  • How about putting eval in front of the execution?
    – jimmij
    Oct 4 at 13:52












up vote
8
down vote

favorite
1









up vote
8
down vote

favorite
1






1





I'm working on a script and I need to build the tar command dynamically.



Here are two examples to illustrate what I'm trying to do :



#!/bin/bash

TAR_ME="/tmp"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
_tar="tar "`printf -- '--exclude="%s" ' "$EXCLUDE[@]"`" -zcf tmp.tar.gz"
echo COMMAND: "$_tar"
$_tar "$TAR_ME"

echo -e "nnNEXT:nn"

EXCLUDE=("--exclude=/tmp/hello hello" "--exclude=/tmp/systemd*" "--exclude=/tmp/Temp*")
_tar="tar "`printf -- '%s ' "$EXCLUDE[@]"`" -zcf test.tar.gz"
echo COMMAND: "$_tar"
$_tar "$TAR_ME"


I want to be able to use _tar as a command, I've been able to make it work with classic path, but I need it to work with spaces in folders' name.
And every single time I got errors that look like :



COMMAND: tar --exclude="/tmp/hello hello" --exclude="/tmp/systemd*" --exclude="/tmp/Temp*" -zcf tmp.tar.gz /tmp
tar: hello": Cannot stat: No such file or directory

COMMAND: tar --exclude=/tmp/hello hello --exclude=/tmp/systemd* --exclude=/tmp/Temp* -zcf test.tar.gz
tar: hello: Cannot stat: No such file or directory


Just one thing you need to know, I need my script to work on very old machines, meaning I can't use last bash features.










share|improve this question









New contributor




ShellCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











I'm working on a script and I need to build the tar command dynamically.



Here are two examples to illustrate what I'm trying to do :



#!/bin/bash

TAR_ME="/tmp"

EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
_tar="tar "`printf -- '--exclude="%s" ' "$EXCLUDE[@]"`" -zcf tmp.tar.gz"
echo COMMAND: "$_tar"
$_tar "$TAR_ME"

echo -e "nnNEXT:nn"

EXCLUDE=("--exclude=/tmp/hello hello" "--exclude=/tmp/systemd*" "--exclude=/tmp/Temp*")
_tar="tar "`printf -- '%s ' "$EXCLUDE[@]"`" -zcf test.tar.gz"
echo COMMAND: "$_tar"
$_tar "$TAR_ME"


I want to be able to use _tar as a command, I've been able to make it work with classic path, but I need it to work with spaces in folders' name.
And every single time I got errors that look like :



COMMAND: tar --exclude="/tmp/hello hello" --exclude="/tmp/systemd*" --exclude="/tmp/Temp*" -zcf tmp.tar.gz /tmp
tar: hello": Cannot stat: No such file or directory

COMMAND: tar --exclude=/tmp/hello hello --exclude=/tmp/systemd* --exclude=/tmp/Temp* -zcf test.tar.gz
tar: hello: Cannot stat: No such file or directory


Just one thing you need to know, I need my script to work on very old machines, meaning I can't use last bash features.







bash shell-script tar string






share|improve this question









New contributor




ShellCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











share|improve this question









New contributor




ShellCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









share|improve this question




share|improve this question








edited Oct 4 at 19:30









Rui F Ribeiro

37k1273117




37k1273117






New contributor




ShellCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.









asked Oct 4 at 13:35









ShellCode

1435




1435




New contributor




ShellCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.





New contributor





ShellCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.






ShellCode is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.











  • I believe the --exclude option can only accept a single string after it. You can have multiple --exclude statements though. Maybe try "--exclude=/tmp/hello --exclude=hello" Oops. Nevermind. I misunderstood.
    – Lewis M
    Oct 4 at 13:43











  • @LewisM I think OP want to exclude directory "/tmp/hello hello" (yes, with a space.
    – Archemar
    Oct 4 at 13:44










  • @ShellCode what about quoting all exclude, e.g. "--exclude=/tmp/hello hello"
    – Archemar
    Oct 4 at 13:45










  • Yeah. That's why I put the Oops statement later. :)
    – Lewis M
    Oct 4 at 13:46










  • How about putting eval in front of the execution?
    – jimmij
    Oct 4 at 13:52
















  • I believe the --exclude option can only accept a single string after it. You can have multiple --exclude statements though. Maybe try "--exclude=/tmp/hello --exclude=hello" Oops. Nevermind. I misunderstood.
    – Lewis M
    Oct 4 at 13:43











  • @LewisM I think OP want to exclude directory "/tmp/hello hello" (yes, with a space.
    – Archemar
    Oct 4 at 13:44










  • @ShellCode what about quoting all exclude, e.g. "--exclude=/tmp/hello hello"
    – Archemar
    Oct 4 at 13:45










  • Yeah. That's why I put the Oops statement later. :)
    – Lewis M
    Oct 4 at 13:46










  • How about putting eval in front of the execution?
    – jimmij
    Oct 4 at 13:52















I believe the --exclude option can only accept a single string after it. You can have multiple --exclude statements though. Maybe try "--exclude=/tmp/hello --exclude=hello" Oops. Nevermind. I misunderstood.
– Lewis M
Oct 4 at 13:43





I believe the --exclude option can only accept a single string after it. You can have multiple --exclude statements though. Maybe try "--exclude=/tmp/hello --exclude=hello" Oops. Nevermind. I misunderstood.
– Lewis M
Oct 4 at 13:43













@LewisM I think OP want to exclude directory "/tmp/hello hello" (yes, with a space.
– Archemar
Oct 4 at 13:44




@LewisM I think OP want to exclude directory "/tmp/hello hello" (yes, with a space.
– Archemar
Oct 4 at 13:44












@ShellCode what about quoting all exclude, e.g. "--exclude=/tmp/hello hello"
– Archemar
Oct 4 at 13:45




@ShellCode what about quoting all exclude, e.g. "--exclude=/tmp/hello hello"
– Archemar
Oct 4 at 13:45












Yeah. That's why I put the Oops statement later. :)
– Lewis M
Oct 4 at 13:46




Yeah. That's why I put the Oops statement later. :)
– Lewis M
Oct 4 at 13:46












How about putting eval in front of the execution?
– jimmij
Oct 4 at 13:52




How about putting eval in front of the execution?
– jimmij
Oct 4 at 13:52










2 Answers
2






active

oldest

votes

















up vote
9
down vote



accepted










Don't try to make an executable string. Instead build the arguments in an array and use that when calling tar (you are already using an array properly for EXCLUDE):



#!/bin/bash

directory=/tmp

exclude=( "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*" )

# Now build the list of "--exclude" options from the exclude array:
for elem in "$exclude[@]"; do
exclude_opts+=( --exclude="$elem" )
done

# Run tar
tar -cz -f tmp.tar.gz "$exclude_opts[@]" "$directory"


With /bin/sh:



#!/bin/sh

directory=/tmp

set -- "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

# Now build the list of "--exclude" options from the $@ array:
for elem do
shift
set -- "$@" --exclude="$elem"
done

# Run tar
tar -cz -f tmp.tar.gz "$@" "$directory"


Note the quoting of $@ in the sh code and of both $exclude[@] and $exclude_opts[@] in the bash code. This ensures that the lists are expanded to individually quoted elements.



Related:



  • How can we run a command stored in a variable?





share|improve this answer





























    up vote
    2
    down vote













    mix()
    p=$1; shift; q=$1; shift; c=
    i=1; for a; do c="$c $q "$$i""; i=$((i+1)); done
    eval "$p%%*$c$p#*%"

    mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

    EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
    mix 'tar % -zcf tmp.tar.gz' --exclude "$EXCLUDE[@]"


    Extending the answer here.
    This doesn't rely on any bashisms, it will also work fine with debian's /bin/sh, and with busybox.






    share|improve this answer






















    • Thank you very much for your help, but I don't really like the eval, it's quite dangerous... Moreover, this code is quite hard to understand, don't you have something easier ? :/ The script will be distributed so I have to keep it as simple as possible...
      – ShellCode
      Oct 4 at 14:03










    • It's not dangerous. Run it with set -x. What exactly you don't understand?
      – mosvy
      Oct 4 at 14:04










    • Also, read the original answer on stackoverflow. It includes a demo.
      – mosvy
      Oct 4 at 14:10










    • It works quite well though... Waiting to see if anybody has a cleaner answer, otherwise I will accept yours. Maybe there is nothing wrong with that code, but every time I see an eval, I'm afraid the code could lead to command injection, that's why I try to avoid it
      – ShellCode
      Oct 4 at 14:13











    • I've updated the answer with a fix for indexes > 9. You can replace the eval with an echo to see what's actually getting (the eval doesn't see the filenames)
      – mosvy
      Oct 4 at 14:29










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



    );






    ShellCode is a new contributor. Be nice, and check out our Code of Conduct.









     

    draft saved


    draft discarded


















    StackExchange.ready(
    function ()
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f473241%2fbuild-a-command-dynamically%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
    9
    down vote



    accepted










    Don't try to make an executable string. Instead build the arguments in an array and use that when calling tar (you are already using an array properly for EXCLUDE):



    #!/bin/bash

    directory=/tmp

    exclude=( "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*" )

    # Now build the list of "--exclude" options from the exclude array:
    for elem in "$exclude[@]"; do
    exclude_opts+=( --exclude="$elem" )
    done

    # Run tar
    tar -cz -f tmp.tar.gz "$exclude_opts[@]" "$directory"


    With /bin/sh:



    #!/bin/sh

    directory=/tmp

    set -- "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

    # Now build the list of "--exclude" options from the $@ array:
    for elem do
    shift
    set -- "$@" --exclude="$elem"
    done

    # Run tar
    tar -cz -f tmp.tar.gz "$@" "$directory"


    Note the quoting of $@ in the sh code and of both $exclude[@] and $exclude_opts[@] in the bash code. This ensures that the lists are expanded to individually quoted elements.



    Related:



    • How can we run a command stored in a variable?





    share|improve this answer


























      up vote
      9
      down vote



      accepted










      Don't try to make an executable string. Instead build the arguments in an array and use that when calling tar (you are already using an array properly for EXCLUDE):



      #!/bin/bash

      directory=/tmp

      exclude=( "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*" )

      # Now build the list of "--exclude" options from the exclude array:
      for elem in "$exclude[@]"; do
      exclude_opts+=( --exclude="$elem" )
      done

      # Run tar
      tar -cz -f tmp.tar.gz "$exclude_opts[@]" "$directory"


      With /bin/sh:



      #!/bin/sh

      directory=/tmp

      set -- "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

      # Now build the list of "--exclude" options from the $@ array:
      for elem do
      shift
      set -- "$@" --exclude="$elem"
      done

      # Run tar
      tar -cz -f tmp.tar.gz "$@" "$directory"


      Note the quoting of $@ in the sh code and of both $exclude[@] and $exclude_opts[@] in the bash code. This ensures that the lists are expanded to individually quoted elements.



      Related:



      • How can we run a command stored in a variable?





      share|improve this answer
























        up vote
        9
        down vote



        accepted







        up vote
        9
        down vote



        accepted






        Don't try to make an executable string. Instead build the arguments in an array and use that when calling tar (you are already using an array properly for EXCLUDE):



        #!/bin/bash

        directory=/tmp

        exclude=( "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*" )

        # Now build the list of "--exclude" options from the exclude array:
        for elem in "$exclude[@]"; do
        exclude_opts+=( --exclude="$elem" )
        done

        # Run tar
        tar -cz -f tmp.tar.gz "$exclude_opts[@]" "$directory"


        With /bin/sh:



        #!/bin/sh

        directory=/tmp

        set -- "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

        # Now build the list of "--exclude" options from the $@ array:
        for elem do
        shift
        set -- "$@" --exclude="$elem"
        done

        # Run tar
        tar -cz -f tmp.tar.gz "$@" "$directory"


        Note the quoting of $@ in the sh code and of both $exclude[@] and $exclude_opts[@] in the bash code. This ensures that the lists are expanded to individually quoted elements.



        Related:



        • How can we run a command stored in a variable?





        share|improve this answer














        Don't try to make an executable string. Instead build the arguments in an array and use that when calling tar (you are already using an array properly for EXCLUDE):



        #!/bin/bash

        directory=/tmp

        exclude=( "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*" )

        # Now build the list of "--exclude" options from the exclude array:
        for elem in "$exclude[@]"; do
        exclude_opts+=( --exclude="$elem" )
        done

        # Run tar
        tar -cz -f tmp.tar.gz "$exclude_opts[@]" "$directory"


        With /bin/sh:



        #!/bin/sh

        directory=/tmp

        set -- "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

        # Now build the list of "--exclude" options from the $@ array:
        for elem do
        shift
        set -- "$@" --exclude="$elem"
        done

        # Run tar
        tar -cz -f tmp.tar.gz "$@" "$directory"


        Note the quoting of $@ in the sh code and of both $exclude[@] and $exclude_opts[@] in the bash code. This ensures that the lists are expanded to individually quoted elements.



        Related:



        • How can we run a command stored in a variable?






        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Oct 4 at 14:27

























        answered Oct 4 at 14:13









        Kusalananda

        108k14210333




        108k14210333






















            up vote
            2
            down vote













            mix()
            p=$1; shift; q=$1; shift; c=
            i=1; for a; do c="$c $q "$$i""; i=$((i+1)); done
            eval "$p%%*$c$p#*%"

            mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

            EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
            mix 'tar % -zcf tmp.tar.gz' --exclude "$EXCLUDE[@]"


            Extending the answer here.
            This doesn't rely on any bashisms, it will also work fine with debian's /bin/sh, and with busybox.






            share|improve this answer






















            • Thank you very much for your help, but I don't really like the eval, it's quite dangerous... Moreover, this code is quite hard to understand, don't you have something easier ? :/ The script will be distributed so I have to keep it as simple as possible...
              – ShellCode
              Oct 4 at 14:03










            • It's not dangerous. Run it with set -x. What exactly you don't understand?
              – mosvy
              Oct 4 at 14:04










            • Also, read the original answer on stackoverflow. It includes a demo.
              – mosvy
              Oct 4 at 14:10










            • It works quite well though... Waiting to see if anybody has a cleaner answer, otherwise I will accept yours. Maybe there is nothing wrong with that code, but every time I see an eval, I'm afraid the code could lead to command injection, that's why I try to avoid it
              – ShellCode
              Oct 4 at 14:13











            • I've updated the answer with a fix for indexes > 9. You can replace the eval with an echo to see what's actually getting (the eval doesn't see the filenames)
              – mosvy
              Oct 4 at 14:29














            up vote
            2
            down vote













            mix()
            p=$1; shift; q=$1; shift; c=
            i=1; for a; do c="$c $q "$$i""; i=$((i+1)); done
            eval "$p%%*$c$p#*%"

            mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

            EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
            mix 'tar % -zcf tmp.tar.gz' --exclude "$EXCLUDE[@]"


            Extending the answer here.
            This doesn't rely on any bashisms, it will also work fine with debian's /bin/sh, and with busybox.






            share|improve this answer






















            • Thank you very much for your help, but I don't really like the eval, it's quite dangerous... Moreover, this code is quite hard to understand, don't you have something easier ? :/ The script will be distributed so I have to keep it as simple as possible...
              – ShellCode
              Oct 4 at 14:03










            • It's not dangerous. Run it with set -x. What exactly you don't understand?
              – mosvy
              Oct 4 at 14:04










            • Also, read the original answer on stackoverflow. It includes a demo.
              – mosvy
              Oct 4 at 14:10










            • It works quite well though... Waiting to see if anybody has a cleaner answer, otherwise I will accept yours. Maybe there is nothing wrong with that code, but every time I see an eval, I'm afraid the code could lead to command injection, that's why I try to avoid it
              – ShellCode
              Oct 4 at 14:13











            • I've updated the answer with a fix for indexes > 9. You can replace the eval with an echo to see what's actually getting (the eval doesn't see the filenames)
              – mosvy
              Oct 4 at 14:29












            up vote
            2
            down vote










            up vote
            2
            down vote









            mix()
            p=$1; shift; q=$1; shift; c=
            i=1; for a; do c="$c $q "$$i""; i=$((i+1)); done
            eval "$p%%*$c$p#*%"

            mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

            EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
            mix 'tar % -zcf tmp.tar.gz' --exclude "$EXCLUDE[@]"


            Extending the answer here.
            This doesn't rely on any bashisms, it will also work fine with debian's /bin/sh, and with busybox.






            share|improve this answer














            mix()
            p=$1; shift; q=$1; shift; c=
            i=1; for a; do c="$c $q "$$i""; i=$((i+1)); done
            eval "$p%%*$c$p#*%"

            mix 'tar % -zcf tmp.tar.gz' --exclude "/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*"

            EXCLUDE=("/tmp/hello hello" "/tmp/systemd*" "/tmp/Temp*")
            mix 'tar % -zcf tmp.tar.gz' --exclude "$EXCLUDE[@]"


            Extending the answer here.
            This doesn't rely on any bashisms, it will also work fine with debian's /bin/sh, and with busybox.







            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Oct 4 at 14:34

























            answered Oct 4 at 13:56









            mosvy

            1,932110




            1,932110











            • Thank you very much for your help, but I don't really like the eval, it's quite dangerous... Moreover, this code is quite hard to understand, don't you have something easier ? :/ The script will be distributed so I have to keep it as simple as possible...
              – ShellCode
              Oct 4 at 14:03










            • It's not dangerous. Run it with set -x. What exactly you don't understand?
              – mosvy
              Oct 4 at 14:04










            • Also, read the original answer on stackoverflow. It includes a demo.
              – mosvy
              Oct 4 at 14:10










            • It works quite well though... Waiting to see if anybody has a cleaner answer, otherwise I will accept yours. Maybe there is nothing wrong with that code, but every time I see an eval, I'm afraid the code could lead to command injection, that's why I try to avoid it
              – ShellCode
              Oct 4 at 14:13











            • I've updated the answer with a fix for indexes > 9. You can replace the eval with an echo to see what's actually getting (the eval doesn't see the filenames)
              – mosvy
              Oct 4 at 14:29
















            • Thank you very much for your help, but I don't really like the eval, it's quite dangerous... Moreover, this code is quite hard to understand, don't you have something easier ? :/ The script will be distributed so I have to keep it as simple as possible...
              – ShellCode
              Oct 4 at 14:03










            • It's not dangerous. Run it with set -x. What exactly you don't understand?
              – mosvy
              Oct 4 at 14:04










            • Also, read the original answer on stackoverflow. It includes a demo.
              – mosvy
              Oct 4 at 14:10










            • It works quite well though... Waiting to see if anybody has a cleaner answer, otherwise I will accept yours. Maybe there is nothing wrong with that code, but every time I see an eval, I'm afraid the code could lead to command injection, that's why I try to avoid it
              – ShellCode
              Oct 4 at 14:13











            • I've updated the answer with a fix for indexes > 9. You can replace the eval with an echo to see what's actually getting (the eval doesn't see the filenames)
              – mosvy
              Oct 4 at 14:29















            Thank you very much for your help, but I don't really like the eval, it's quite dangerous... Moreover, this code is quite hard to understand, don't you have something easier ? :/ The script will be distributed so I have to keep it as simple as possible...
            – ShellCode
            Oct 4 at 14:03




            Thank you very much for your help, but I don't really like the eval, it's quite dangerous... Moreover, this code is quite hard to understand, don't you have something easier ? :/ The script will be distributed so I have to keep it as simple as possible...
            – ShellCode
            Oct 4 at 14:03












            It's not dangerous. Run it with set -x. What exactly you don't understand?
            – mosvy
            Oct 4 at 14:04




            It's not dangerous. Run it with set -x. What exactly you don't understand?
            – mosvy
            Oct 4 at 14:04












            Also, read the original answer on stackoverflow. It includes a demo.
            – mosvy
            Oct 4 at 14:10




            Also, read the original answer on stackoverflow. It includes a demo.
            – mosvy
            Oct 4 at 14:10












            It works quite well though... Waiting to see if anybody has a cleaner answer, otherwise I will accept yours. Maybe there is nothing wrong with that code, but every time I see an eval, I'm afraid the code could lead to command injection, that's why I try to avoid it
            – ShellCode
            Oct 4 at 14:13





            It works quite well though... Waiting to see if anybody has a cleaner answer, otherwise I will accept yours. Maybe there is nothing wrong with that code, but every time I see an eval, I'm afraid the code could lead to command injection, that's why I try to avoid it
            – ShellCode
            Oct 4 at 14:13













            I've updated the answer with a fix for indexes > 9. You can replace the eval with an echo to see what's actually getting (the eval doesn't see the filenames)
            – mosvy
            Oct 4 at 14:29




            I've updated the answer with a fix for indexes > 9. You can replace the eval with an echo to see what's actually getting (the eval doesn't see the filenames)
            – mosvy
            Oct 4 at 14:29










            ShellCode is a new contributor. Be nice, and check out our Code of Conduct.









             

            draft saved


            draft discarded


















            ShellCode is a new contributor. Be nice, and check out our Code of Conduct.












            ShellCode is a new contributor. Be nice, and check out our Code of Conduct.











            ShellCode is a new contributor. Be nice, and check out our Code of Conduct.













             


            draft saved


            draft discarded














            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f473241%2fbuild-a-command-dynamically%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?