Store command in a variable without evaluation - Unix [closed]

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











up vote
-3
down vote

favorite












I am trying to store a command in a variable, so that it can be run on a remote server later. The asterisk is being replaced with the folder names and is being stored in the variable. I need the command to be as it is with the asterisk fir later usage.



Script:



#!/bin/bash
cmd="ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1"
echo $cmd


Output:



./script.sh 
ls -lrt /client/folder299/version_1 /client/ifolder299/ifolder/version_a /client/ifolder300/ifolder1/version_b /client/ifolder301/ifolder2/version_c /client/ifolder302/ifolder3/version_d | grep 299 | tail -1


I tried searching around with no luck. Could someone help me with a way to store the command as it is?







share|improve this question













closed as unclear what you're asking by Kusalananda, schily, Anthony Geoghegan, G-Man, thrig Jul 12 at 13:58


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.














  • check this post unix.stackexchange.com/questions/87405/…
    – Kamaraj
    Jul 11 at 6:34






  • 1




    Why are you trying to store a command pipeline in a variable? That's almost certainly the wrong thing to do. Also, your script lacks a #! line. See unix.stackexchange.com/questions/444946
    – Kusalananda
    Jul 11 at 6:47







  • 1




    I can not reproduce this issue with bash. The string is stored and outputted as is. The only thing is that you're echoing the expanded variable unquoted, which would invoke filename globbing. Using printf '%sn' "$cmd" would prevent that (or even echo "$cmd"). But the command would never be evaluated (executed).
    – Kusalananda
    Jul 11 at 6:56







  • 1




    Could you please clarify what you mean by "the command is evaluated"? Does it run the pipeline and store the result of the final tail -1 in cmd?
    – Kusalananda
    Jul 11 at 7:12






  • 1




    @Raj The bash shell just does not do that.
    – Kusalananda
    Jul 11 at 8:50














up vote
-3
down vote

favorite












I am trying to store a command in a variable, so that it can be run on a remote server later. The asterisk is being replaced with the folder names and is being stored in the variable. I need the command to be as it is with the asterisk fir later usage.



Script:



#!/bin/bash
cmd="ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1"
echo $cmd


Output:



./script.sh 
ls -lrt /client/folder299/version_1 /client/ifolder299/ifolder/version_a /client/ifolder300/ifolder1/version_b /client/ifolder301/ifolder2/version_c /client/ifolder302/ifolder3/version_d | grep 299 | tail -1


I tried searching around with no luck. Could someone help me with a way to store the command as it is?







share|improve this question













closed as unclear what you're asking by Kusalananda, schily, Anthony Geoghegan, G-Man, thrig Jul 12 at 13:58


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.














  • check this post unix.stackexchange.com/questions/87405/…
    – Kamaraj
    Jul 11 at 6:34






  • 1




    Why are you trying to store a command pipeline in a variable? That's almost certainly the wrong thing to do. Also, your script lacks a #! line. See unix.stackexchange.com/questions/444946
    – Kusalananda
    Jul 11 at 6:47







  • 1




    I can not reproduce this issue with bash. The string is stored and outputted as is. The only thing is that you're echoing the expanded variable unquoted, which would invoke filename globbing. Using printf '%sn' "$cmd" would prevent that (or even echo "$cmd"). But the command would never be evaluated (executed).
    – Kusalananda
    Jul 11 at 6:56







  • 1




    Could you please clarify what you mean by "the command is evaluated"? Does it run the pipeline and store the result of the final tail -1 in cmd?
    – Kusalananda
    Jul 11 at 7:12






  • 1




    @Raj The bash shell just does not do that.
    – Kusalananda
    Jul 11 at 8:50












up vote
-3
down vote

favorite









up vote
-3
down vote

favorite











I am trying to store a command in a variable, so that it can be run on a remote server later. The asterisk is being replaced with the folder names and is being stored in the variable. I need the command to be as it is with the asterisk fir later usage.



Script:



#!/bin/bash
cmd="ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1"
echo $cmd


Output:



./script.sh 
ls -lrt /client/folder299/version_1 /client/ifolder299/ifolder/version_a /client/ifolder300/ifolder1/version_b /client/ifolder301/ifolder2/version_c /client/ifolder302/ifolder3/version_d | grep 299 | tail -1


I tried searching around with no luck. Could someone help me with a way to store the command as it is?







share|improve this question













I am trying to store a command in a variable, so that it can be run on a remote server later. The asterisk is being replaced with the folder names and is being stored in the variable. I need the command to be as it is with the asterisk fir later usage.



Script:



#!/bin/bash
cmd="ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1"
echo $cmd


Output:



./script.sh 
ls -lrt /client/folder299/version_1 /client/ifolder299/ifolder/version_a /client/ifolder300/ifolder1/version_b /client/ifolder301/ifolder2/version_c /client/ifolder302/ifolder3/version_d | grep 299 | tail -1


I tried searching around with no luck. Could someone help me with a way to store the command as it is?









share|improve this question












share|improve this question




share|improve this question








edited Jul 13 at 12:34
























asked Jul 11 at 6:28









Raj

36




36




closed as unclear what you're asking by Kusalananda, schily, Anthony Geoghegan, G-Man, thrig Jul 12 at 13:58


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.






closed as unclear what you're asking by Kusalananda, schily, Anthony Geoghegan, G-Man, thrig Jul 12 at 13:58


Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.













  • check this post unix.stackexchange.com/questions/87405/…
    – Kamaraj
    Jul 11 at 6:34






  • 1




    Why are you trying to store a command pipeline in a variable? That's almost certainly the wrong thing to do. Also, your script lacks a #! line. See unix.stackexchange.com/questions/444946
    – Kusalananda
    Jul 11 at 6:47







  • 1




    I can not reproduce this issue with bash. The string is stored and outputted as is. The only thing is that you're echoing the expanded variable unquoted, which would invoke filename globbing. Using printf '%sn' "$cmd" would prevent that (or even echo "$cmd"). But the command would never be evaluated (executed).
    – Kusalananda
    Jul 11 at 6:56







  • 1




    Could you please clarify what you mean by "the command is evaluated"? Does it run the pipeline and store the result of the final tail -1 in cmd?
    – Kusalananda
    Jul 11 at 7:12






  • 1




    @Raj The bash shell just does not do that.
    – Kusalananda
    Jul 11 at 8:50
















  • check this post unix.stackexchange.com/questions/87405/…
    – Kamaraj
    Jul 11 at 6:34






  • 1




    Why are you trying to store a command pipeline in a variable? That's almost certainly the wrong thing to do. Also, your script lacks a #! line. See unix.stackexchange.com/questions/444946
    – Kusalananda
    Jul 11 at 6:47







  • 1




    I can not reproduce this issue with bash. The string is stored and outputted as is. The only thing is that you're echoing the expanded variable unquoted, which would invoke filename globbing. Using printf '%sn' "$cmd" would prevent that (or even echo "$cmd"). But the command would never be evaluated (executed).
    – Kusalananda
    Jul 11 at 6:56







  • 1




    Could you please clarify what you mean by "the command is evaluated"? Does it run the pipeline and store the result of the final tail -1 in cmd?
    – Kusalananda
    Jul 11 at 7:12






  • 1




    @Raj The bash shell just does not do that.
    – Kusalananda
    Jul 11 at 8:50















check this post unix.stackexchange.com/questions/87405/…
– Kamaraj
Jul 11 at 6:34




check this post unix.stackexchange.com/questions/87405/…
– Kamaraj
Jul 11 at 6:34




1




1




Why are you trying to store a command pipeline in a variable? That's almost certainly the wrong thing to do. Also, your script lacks a #! line. See unix.stackexchange.com/questions/444946
– Kusalananda
Jul 11 at 6:47





Why are you trying to store a command pipeline in a variable? That's almost certainly the wrong thing to do. Also, your script lacks a #! line. See unix.stackexchange.com/questions/444946
– Kusalananda
Jul 11 at 6:47





1




1




I can not reproduce this issue with bash. The string is stored and outputted as is. The only thing is that you're echoing the expanded variable unquoted, which would invoke filename globbing. Using printf '%sn' "$cmd" would prevent that (or even echo "$cmd"). But the command would never be evaluated (executed).
– Kusalananda
Jul 11 at 6:56





I can not reproduce this issue with bash. The string is stored and outputted as is. The only thing is that you're echoing the expanded variable unquoted, which would invoke filename globbing. Using printf '%sn' "$cmd" would prevent that (or even echo "$cmd"). But the command would never be evaluated (executed).
– Kusalananda
Jul 11 at 6:56





1




1




Could you please clarify what you mean by "the command is evaluated"? Does it run the pipeline and store the result of the final tail -1 in cmd?
– Kusalananda
Jul 11 at 7:12




Could you please clarify what you mean by "the command is evaluated"? Does it run the pipeline and store the result of the final tail -1 in cmd?
– Kusalananda
Jul 11 at 7:12




1




1




@Raj The bash shell just does not do that.
– Kusalananda
Jul 11 at 8:50




@Raj The bash shell just does not do that.
– Kusalananda
Jul 11 at 8:50










4 Answers
4






active

oldest

votes

















up vote
1
down vote



accepted










The command is not evaluated and the string is stored as is in the variable. It's the globbing patterns that are expanded when you output the unquoted variable.




cmd="ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1"


This is safe and would set cmd to the literal string ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1. The difference between using double quotes and single quotes around the string doesn't matter in this case (but I would have used single quotes as this is a static string). It doesn't matter in the sense that there is no expansion of anything for the shell to do in the string. Had there been variables or command substitutions in the string, the shell would have expanded those, but there are none.



When you output the value of the variable using echo $cmd, the globbing patterns would be expanded (this is what happens), but the command would still not be run.



To stop the globbing patterns from being expanded, double quote the variable expansion as "$cmd". Personally, I would use



printf '%sn' "$cmd"


to print its value. See "Why is printf better than echo?" for why.



Related:



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


Note also that since you're parsing the output of ls -l (which in itself is not safe), and then grepping for a number, you would pick that number up from anywhere in the ls -l output, for example in the size of a file.



I would advise that you rethink what the bigger picture issue is that you're trying to solve, and then that you ask a brand new question about that instead.



To find the most recently modified regular file out of a list of pathnames, you may do



unset newest
for pathname in /client/*/ver* /client/*/*/ver*; do
if [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
newest=$pathname
fi
done


This is assuming that the filename globbing patterns that you've mentioned expands to the names that you'd like to check. To additionally restrict this to only allow filenames containing the string 299:



unset newest
for pathname in /client/*/ver* /client/*/*/ver*; do
if [[ "$pathname##*/" == *299* ]] &&
[ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
newest=$pathname
fi
done


If the globbing patterns expand to directories that you need to look into recursively, then using bash:



shopt -s globstar
unset newest
for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
if [[ "$pathname##*/" == *299* ]] &&
[ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
newest=$pathname
fi
done


Example of running this over SSH:



ssh user@host bash -s -O globstar <<'END_SCRIPT'
for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
if [[ "$pathname##*/" == *299* ]] &&
[ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
newest=$pathname
fi
done
printf 'Newest file: %sn' "$newest"
END_SCRIPT





share|improve this answer























  • Thanks for the script. I am trying to use the last example provided above, but it doesn't print the file. Tried searching around and found this stackoverflow.com/a/26766782/9316558. This script works in printing the latest file, but I have trouble modifying it to match a pattern (299).
    – Raj
    Jul 19 at 6:57











  • @Raj Does the globbing patterns /client/*/ver* and /client/*/*/ver* resolve to directory names or to filenames that may contain 299?
    – Kusalananda
    Jul 19 at 7:01










  • 299 is a string in folder name. Eg : ` /client/folder299/version_1 ` ` /client/ifolder299/ifolder/version_a ` . Basically I am trying get the latest version of the server ID 299 (In this case either version_1 or version_a). Please let me know if something is not clear.
    – Raj
    Jul 19 at 8:07










  • @Raj Ah, this was unclear from the question. It is also sufficiently different from the actual question that I'm not going to answer it here. Instead, I suggest that you ask a new question about this specifically, and there mention that you'd like to find a particular file in a particular path, and what this file is for etc.
    – Kusalananda
    Jul 19 at 8:12










  • I agree with you. unix.stackexchange.com/q/457157/250029 opened for it.
    – Raj
    Jul 19 at 8:50

















up vote
0
down vote













May be the option f :



$ touch /tmp/filetmp
$ c="ls /tmp/*"

$ set -f
$ echo $c
ls /tmp/*

$ set +f
$ echo $c
ls /tmp/filetmp

$ rm /tmp/filetmp
$ unset c


Under linux, usually by default the option is +f






share|improve this answer






























    up vote
    0
    down vote













    Sorry for the above confusion.



    The issue is resolved with providing the command directly in the following way.



    ssh username@host "ls -lrt /client/*/ver* /client/*/*/ver* | grep $4 | tail -1" 





    share|improve this answer























    • If you had said something about how you were going to use the string, we would have found a solution for you much quicker. Note that this command would still give you false positives if the grep matches anything that isn't a filename in the ls output. Also, since $4 is unquoted, filename matching and word splitting will occur on its value. This is not the command you would want to use in a production system.
      – Kusalananda
      Jul 18 at 7:17










    • @Kusalananda Thanks for the insight. As you understood, I want to get the latest file from the remote system for a provided server number. I am using the above command, where the $4 represents the server number. Are you suggesting that quoting the $4 would be better or is there a better approach towards it. I am an amateur in shell, trying to automate what we do manually.
      – Raj
      Jul 18 at 8:22










    • I have doodled a bit at the end of my answer.
      – Kusalananda
      Jul 18 at 9:36

















    up vote
    -2
    down vote













    Use single quote while storing the commands into variable. Use double quotes while using in echo command.



    $ cmd='ls -lrt /var/* /tmp/* /home/* | grep test | tail -1'
    $ echo "$cmd"
    ls -lrt /var/* /tmp/* /home/* | grep test | tail -1


    Difference between single and double quotes






    share|improve this answer























    • The double quotes used when assigning to cmd is not an issue here as the string doesn't contain anything that the shell would expand. Double quoting the expansion when printing the value is important though. It still doesn't explain why, on the user's system, it actually runs the command (which I haven't been able to replicate).
      – Kusalananda
      Jul 11 at 7:10










    • @Kamaraj , Thanks for the response. The single quote also doesn't seem to work. The expression in the quotes is being evaluated(I mean, the output we get when this command is executed on the command line) and stored in the variable.
      – Raj
      Jul 11 at 8:58

















    4 Answers
    4






    active

    oldest

    votes








    4 Answers
    4






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes








    up vote
    1
    down vote



    accepted










    The command is not evaluated and the string is stored as is in the variable. It's the globbing patterns that are expanded when you output the unquoted variable.




    cmd="ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1"


    This is safe and would set cmd to the literal string ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1. The difference between using double quotes and single quotes around the string doesn't matter in this case (but I would have used single quotes as this is a static string). It doesn't matter in the sense that there is no expansion of anything for the shell to do in the string. Had there been variables or command substitutions in the string, the shell would have expanded those, but there are none.



    When you output the value of the variable using echo $cmd, the globbing patterns would be expanded (this is what happens), but the command would still not be run.



    To stop the globbing patterns from being expanded, double quote the variable expansion as "$cmd". Personally, I would use



    printf '%sn' "$cmd"


    to print its value. See "Why is printf better than echo?" for why.



    Related:



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


    Note also that since you're parsing the output of ls -l (which in itself is not safe), and then grepping for a number, you would pick that number up from anywhere in the ls -l output, for example in the size of a file.



    I would advise that you rethink what the bigger picture issue is that you're trying to solve, and then that you ask a brand new question about that instead.



    To find the most recently modified regular file out of a list of pathnames, you may do



    unset newest
    for pathname in /client/*/ver* /client/*/*/ver*; do
    if [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    This is assuming that the filename globbing patterns that you've mentioned expands to the names that you'd like to check. To additionally restrict this to only allow filenames containing the string 299:



    unset newest
    for pathname in /client/*/ver* /client/*/*/ver*; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    If the globbing patterns expand to directories that you need to look into recursively, then using bash:



    shopt -s globstar
    unset newest
    for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    Example of running this over SSH:



    ssh user@host bash -s -O globstar <<'END_SCRIPT'
    for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done
    printf 'Newest file: %sn' "$newest"
    END_SCRIPT





    share|improve this answer























    • Thanks for the script. I am trying to use the last example provided above, but it doesn't print the file. Tried searching around and found this stackoverflow.com/a/26766782/9316558. This script works in printing the latest file, but I have trouble modifying it to match a pattern (299).
      – Raj
      Jul 19 at 6:57











    • @Raj Does the globbing patterns /client/*/ver* and /client/*/*/ver* resolve to directory names or to filenames that may contain 299?
      – Kusalananda
      Jul 19 at 7:01










    • 299 is a string in folder name. Eg : ` /client/folder299/version_1 ` ` /client/ifolder299/ifolder/version_a ` . Basically I am trying get the latest version of the server ID 299 (In this case either version_1 or version_a). Please let me know if something is not clear.
      – Raj
      Jul 19 at 8:07










    • @Raj Ah, this was unclear from the question. It is also sufficiently different from the actual question that I'm not going to answer it here. Instead, I suggest that you ask a new question about this specifically, and there mention that you'd like to find a particular file in a particular path, and what this file is for etc.
      – Kusalananda
      Jul 19 at 8:12










    • I agree with you. unix.stackexchange.com/q/457157/250029 opened for it.
      – Raj
      Jul 19 at 8:50














    up vote
    1
    down vote



    accepted










    The command is not evaluated and the string is stored as is in the variable. It's the globbing patterns that are expanded when you output the unquoted variable.




    cmd="ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1"


    This is safe and would set cmd to the literal string ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1. The difference between using double quotes and single quotes around the string doesn't matter in this case (but I would have used single quotes as this is a static string). It doesn't matter in the sense that there is no expansion of anything for the shell to do in the string. Had there been variables or command substitutions in the string, the shell would have expanded those, but there are none.



    When you output the value of the variable using echo $cmd, the globbing patterns would be expanded (this is what happens), but the command would still not be run.



    To stop the globbing patterns from being expanded, double quote the variable expansion as "$cmd". Personally, I would use



    printf '%sn' "$cmd"


    to print its value. See "Why is printf better than echo?" for why.



    Related:



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


    Note also that since you're parsing the output of ls -l (which in itself is not safe), and then grepping for a number, you would pick that number up from anywhere in the ls -l output, for example in the size of a file.



    I would advise that you rethink what the bigger picture issue is that you're trying to solve, and then that you ask a brand new question about that instead.



    To find the most recently modified regular file out of a list of pathnames, you may do



    unset newest
    for pathname in /client/*/ver* /client/*/*/ver*; do
    if [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    This is assuming that the filename globbing patterns that you've mentioned expands to the names that you'd like to check. To additionally restrict this to only allow filenames containing the string 299:



    unset newest
    for pathname in /client/*/ver* /client/*/*/ver*; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    If the globbing patterns expand to directories that you need to look into recursively, then using bash:



    shopt -s globstar
    unset newest
    for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    Example of running this over SSH:



    ssh user@host bash -s -O globstar <<'END_SCRIPT'
    for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done
    printf 'Newest file: %sn' "$newest"
    END_SCRIPT





    share|improve this answer























    • Thanks for the script. I am trying to use the last example provided above, but it doesn't print the file. Tried searching around and found this stackoverflow.com/a/26766782/9316558. This script works in printing the latest file, but I have trouble modifying it to match a pattern (299).
      – Raj
      Jul 19 at 6:57











    • @Raj Does the globbing patterns /client/*/ver* and /client/*/*/ver* resolve to directory names or to filenames that may contain 299?
      – Kusalananda
      Jul 19 at 7:01










    • 299 is a string in folder name. Eg : ` /client/folder299/version_1 ` ` /client/ifolder299/ifolder/version_a ` . Basically I am trying get the latest version of the server ID 299 (In this case either version_1 or version_a). Please let me know if something is not clear.
      – Raj
      Jul 19 at 8:07










    • @Raj Ah, this was unclear from the question. It is also sufficiently different from the actual question that I'm not going to answer it here. Instead, I suggest that you ask a new question about this specifically, and there mention that you'd like to find a particular file in a particular path, and what this file is for etc.
      – Kusalananda
      Jul 19 at 8:12










    • I agree with you. unix.stackexchange.com/q/457157/250029 opened for it.
      – Raj
      Jul 19 at 8:50












    up vote
    1
    down vote



    accepted







    up vote
    1
    down vote



    accepted






    The command is not evaluated and the string is stored as is in the variable. It's the globbing patterns that are expanded when you output the unquoted variable.




    cmd="ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1"


    This is safe and would set cmd to the literal string ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1. The difference between using double quotes and single quotes around the string doesn't matter in this case (but I would have used single quotes as this is a static string). It doesn't matter in the sense that there is no expansion of anything for the shell to do in the string. Had there been variables or command substitutions in the string, the shell would have expanded those, but there are none.



    When you output the value of the variable using echo $cmd, the globbing patterns would be expanded (this is what happens), but the command would still not be run.



    To stop the globbing patterns from being expanded, double quote the variable expansion as "$cmd". Personally, I would use



    printf '%sn' "$cmd"


    to print its value. See "Why is printf better than echo?" for why.



    Related:



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


    Note also that since you're parsing the output of ls -l (which in itself is not safe), and then grepping for a number, you would pick that number up from anywhere in the ls -l output, for example in the size of a file.



    I would advise that you rethink what the bigger picture issue is that you're trying to solve, and then that you ask a brand new question about that instead.



    To find the most recently modified regular file out of a list of pathnames, you may do



    unset newest
    for pathname in /client/*/ver* /client/*/*/ver*; do
    if [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    This is assuming that the filename globbing patterns that you've mentioned expands to the names that you'd like to check. To additionally restrict this to only allow filenames containing the string 299:



    unset newest
    for pathname in /client/*/ver* /client/*/*/ver*; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    If the globbing patterns expand to directories that you need to look into recursively, then using bash:



    shopt -s globstar
    unset newest
    for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    Example of running this over SSH:



    ssh user@host bash -s -O globstar <<'END_SCRIPT'
    for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done
    printf 'Newest file: %sn' "$newest"
    END_SCRIPT





    share|improve this answer















    The command is not evaluated and the string is stored as is in the variable. It's the globbing patterns that are expanded when you output the unquoted variable.




    cmd="ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1"


    This is safe and would set cmd to the literal string ls -lrt /client/*/ver* /client/*/*/ver* | grep 299 | tail -1. The difference between using double quotes and single quotes around the string doesn't matter in this case (but I would have used single quotes as this is a static string). It doesn't matter in the sense that there is no expansion of anything for the shell to do in the string. Had there been variables or command substitutions in the string, the shell would have expanded those, but there are none.



    When you output the value of the variable using echo $cmd, the globbing patterns would be expanded (this is what happens), but the command would still not be run.



    To stop the globbing patterns from being expanded, double quote the variable expansion as "$cmd". Personally, I would use



    printf '%sn' "$cmd"


    to print its value. See "Why is printf better than echo?" for why.



    Related:



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


    Note also that since you're parsing the output of ls -l (which in itself is not safe), and then grepping for a number, you would pick that number up from anywhere in the ls -l output, for example in the size of a file.



    I would advise that you rethink what the bigger picture issue is that you're trying to solve, and then that you ask a brand new question about that instead.



    To find the most recently modified regular file out of a list of pathnames, you may do



    unset newest
    for pathname in /client/*/ver* /client/*/*/ver*; do
    if [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    This is assuming that the filename globbing patterns that you've mentioned expands to the names that you'd like to check. To additionally restrict this to only allow filenames containing the string 299:



    unset newest
    for pathname in /client/*/ver* /client/*/*/ver*; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    If the globbing patterns expand to directories that you need to look into recursively, then using bash:



    shopt -s globstar
    unset newest
    for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done


    Example of running this over SSH:



    ssh user@host bash -s -O globstar <<'END_SCRIPT'
    for pathname in /client/*/ver*/** /client/*/*/ver*/**; do
    if [[ "$pathname##*/" == *299* ]] &&
    [ -f "$pathname" ] && [ "$pathname" -nt "$newest" ]; then
    newest=$pathname
    fi
    done
    printf 'Newest file: %sn' "$newest"
    END_SCRIPT






    share|improve this answer















    share|improve this answer



    share|improve this answer








    edited Jul 18 at 9:33


























    answered Jul 11 at 8:58









    Kusalananda

    101k13199312




    101k13199312











    • Thanks for the script. I am trying to use the last example provided above, but it doesn't print the file. Tried searching around and found this stackoverflow.com/a/26766782/9316558. This script works in printing the latest file, but I have trouble modifying it to match a pattern (299).
      – Raj
      Jul 19 at 6:57











    • @Raj Does the globbing patterns /client/*/ver* and /client/*/*/ver* resolve to directory names or to filenames that may contain 299?
      – Kusalananda
      Jul 19 at 7:01










    • 299 is a string in folder name. Eg : ` /client/folder299/version_1 ` ` /client/ifolder299/ifolder/version_a ` . Basically I am trying get the latest version of the server ID 299 (In this case either version_1 or version_a). Please let me know if something is not clear.
      – Raj
      Jul 19 at 8:07










    • @Raj Ah, this was unclear from the question. It is also sufficiently different from the actual question that I'm not going to answer it here. Instead, I suggest that you ask a new question about this specifically, and there mention that you'd like to find a particular file in a particular path, and what this file is for etc.
      – Kusalananda
      Jul 19 at 8:12










    • I agree with you. unix.stackexchange.com/q/457157/250029 opened for it.
      – Raj
      Jul 19 at 8:50
















    • Thanks for the script. I am trying to use the last example provided above, but it doesn't print the file. Tried searching around and found this stackoverflow.com/a/26766782/9316558. This script works in printing the latest file, but I have trouble modifying it to match a pattern (299).
      – Raj
      Jul 19 at 6:57











    • @Raj Does the globbing patterns /client/*/ver* and /client/*/*/ver* resolve to directory names or to filenames that may contain 299?
      – Kusalananda
      Jul 19 at 7:01










    • 299 is a string in folder name. Eg : ` /client/folder299/version_1 ` ` /client/ifolder299/ifolder/version_a ` . Basically I am trying get the latest version of the server ID 299 (In this case either version_1 or version_a). Please let me know if something is not clear.
      – Raj
      Jul 19 at 8:07










    • @Raj Ah, this was unclear from the question. It is also sufficiently different from the actual question that I'm not going to answer it here. Instead, I suggest that you ask a new question about this specifically, and there mention that you'd like to find a particular file in a particular path, and what this file is for etc.
      – Kusalananda
      Jul 19 at 8:12










    • I agree with you. unix.stackexchange.com/q/457157/250029 opened for it.
      – Raj
      Jul 19 at 8:50















    Thanks for the script. I am trying to use the last example provided above, but it doesn't print the file. Tried searching around and found this stackoverflow.com/a/26766782/9316558. This script works in printing the latest file, but I have trouble modifying it to match a pattern (299).
    – Raj
    Jul 19 at 6:57





    Thanks for the script. I am trying to use the last example provided above, but it doesn't print the file. Tried searching around and found this stackoverflow.com/a/26766782/9316558. This script works in printing the latest file, but I have trouble modifying it to match a pattern (299).
    – Raj
    Jul 19 at 6:57













    @Raj Does the globbing patterns /client/*/ver* and /client/*/*/ver* resolve to directory names or to filenames that may contain 299?
    – Kusalananda
    Jul 19 at 7:01




    @Raj Does the globbing patterns /client/*/ver* and /client/*/*/ver* resolve to directory names or to filenames that may contain 299?
    – Kusalananda
    Jul 19 at 7:01












    299 is a string in folder name. Eg : ` /client/folder299/version_1 ` ` /client/ifolder299/ifolder/version_a ` . Basically I am trying get the latest version of the server ID 299 (In this case either version_1 or version_a). Please let me know if something is not clear.
    – Raj
    Jul 19 at 8:07




    299 is a string in folder name. Eg : ` /client/folder299/version_1 ` ` /client/ifolder299/ifolder/version_a ` . Basically I am trying get the latest version of the server ID 299 (In this case either version_1 or version_a). Please let me know if something is not clear.
    – Raj
    Jul 19 at 8:07












    @Raj Ah, this was unclear from the question. It is also sufficiently different from the actual question that I'm not going to answer it here. Instead, I suggest that you ask a new question about this specifically, and there mention that you'd like to find a particular file in a particular path, and what this file is for etc.
    – Kusalananda
    Jul 19 at 8:12




    @Raj Ah, this was unclear from the question. It is also sufficiently different from the actual question that I'm not going to answer it here. Instead, I suggest that you ask a new question about this specifically, and there mention that you'd like to find a particular file in a particular path, and what this file is for etc.
    – Kusalananda
    Jul 19 at 8:12












    I agree with you. unix.stackexchange.com/q/457157/250029 opened for it.
    – Raj
    Jul 19 at 8:50




    I agree with you. unix.stackexchange.com/q/457157/250029 opened for it.
    – Raj
    Jul 19 at 8:50












    up vote
    0
    down vote













    May be the option f :



    $ touch /tmp/filetmp
    $ c="ls /tmp/*"

    $ set -f
    $ echo $c
    ls /tmp/*

    $ set +f
    $ echo $c
    ls /tmp/filetmp

    $ rm /tmp/filetmp
    $ unset c


    Under linux, usually by default the option is +f






    share|improve this answer



























      up vote
      0
      down vote













      May be the option f :



      $ touch /tmp/filetmp
      $ c="ls /tmp/*"

      $ set -f
      $ echo $c
      ls /tmp/*

      $ set +f
      $ echo $c
      ls /tmp/filetmp

      $ rm /tmp/filetmp
      $ unset c


      Under linux, usually by default the option is +f






      share|improve this answer

























        up vote
        0
        down vote










        up vote
        0
        down vote









        May be the option f :



        $ touch /tmp/filetmp
        $ c="ls /tmp/*"

        $ set -f
        $ echo $c
        ls /tmp/*

        $ set +f
        $ echo $c
        ls /tmp/filetmp

        $ rm /tmp/filetmp
        $ unset c


        Under linux, usually by default the option is +f






        share|improve this answer















        May be the option f :



        $ touch /tmp/filetmp
        $ c="ls /tmp/*"

        $ set -f
        $ echo $c
        ls /tmp/*

        $ set +f
        $ echo $c
        ls /tmp/filetmp

        $ rm /tmp/filetmp
        $ unset c


        Under linux, usually by default the option is +f







        share|improve this answer















        share|improve this answer



        share|improve this answer








        edited Jul 11 at 10:56


























        answered Jul 11 at 10:51









        alux

        364




        364




















            up vote
            0
            down vote













            Sorry for the above confusion.



            The issue is resolved with providing the command directly in the following way.



            ssh username@host "ls -lrt /client/*/ver* /client/*/*/ver* | grep $4 | tail -1" 





            share|improve this answer























            • If you had said something about how you were going to use the string, we would have found a solution for you much quicker. Note that this command would still give you false positives if the grep matches anything that isn't a filename in the ls output. Also, since $4 is unquoted, filename matching and word splitting will occur on its value. This is not the command you would want to use in a production system.
              – Kusalananda
              Jul 18 at 7:17










            • @Kusalananda Thanks for the insight. As you understood, I want to get the latest file from the remote system for a provided server number. I am using the above command, where the $4 represents the server number. Are you suggesting that quoting the $4 would be better or is there a better approach towards it. I am an amateur in shell, trying to automate what we do manually.
              – Raj
              Jul 18 at 8:22










            • I have doodled a bit at the end of my answer.
              – Kusalananda
              Jul 18 at 9:36














            up vote
            0
            down vote













            Sorry for the above confusion.



            The issue is resolved with providing the command directly in the following way.



            ssh username@host "ls -lrt /client/*/ver* /client/*/*/ver* | grep $4 | tail -1" 





            share|improve this answer























            • If you had said something about how you were going to use the string, we would have found a solution for you much quicker. Note that this command would still give you false positives if the grep matches anything that isn't a filename in the ls output. Also, since $4 is unquoted, filename matching and word splitting will occur on its value. This is not the command you would want to use in a production system.
              – Kusalananda
              Jul 18 at 7:17










            • @Kusalananda Thanks for the insight. As you understood, I want to get the latest file from the remote system for a provided server number. I am using the above command, where the $4 represents the server number. Are you suggesting that quoting the $4 would be better or is there a better approach towards it. I am an amateur in shell, trying to automate what we do manually.
              – Raj
              Jul 18 at 8:22










            • I have doodled a bit at the end of my answer.
              – Kusalananda
              Jul 18 at 9:36












            up vote
            0
            down vote










            up vote
            0
            down vote









            Sorry for the above confusion.



            The issue is resolved with providing the command directly in the following way.



            ssh username@host "ls -lrt /client/*/ver* /client/*/*/ver* | grep $4 | tail -1" 





            share|improve this answer















            Sorry for the above confusion.



            The issue is resolved with providing the command directly in the following way.



            ssh username@host "ls -lrt /client/*/ver* /client/*/*/ver* | grep $4 | tail -1" 






            share|improve this answer















            share|improve this answer



            share|improve this answer








            edited Jul 13 at 11:27


























            answered Jul 12 at 11:28









            Raj

            36




            36











            • If you had said something about how you were going to use the string, we would have found a solution for you much quicker. Note that this command would still give you false positives if the grep matches anything that isn't a filename in the ls output. Also, since $4 is unquoted, filename matching and word splitting will occur on its value. This is not the command you would want to use in a production system.
              – Kusalananda
              Jul 18 at 7:17










            • @Kusalananda Thanks for the insight. As you understood, I want to get the latest file from the remote system for a provided server number. I am using the above command, where the $4 represents the server number. Are you suggesting that quoting the $4 would be better or is there a better approach towards it. I am an amateur in shell, trying to automate what we do manually.
              – Raj
              Jul 18 at 8:22










            • I have doodled a bit at the end of my answer.
              – Kusalananda
              Jul 18 at 9:36
















            • If you had said something about how you were going to use the string, we would have found a solution for you much quicker. Note that this command would still give you false positives if the grep matches anything that isn't a filename in the ls output. Also, since $4 is unquoted, filename matching and word splitting will occur on its value. This is not the command you would want to use in a production system.
              – Kusalananda
              Jul 18 at 7:17










            • @Kusalananda Thanks for the insight. As you understood, I want to get the latest file from the remote system for a provided server number. I am using the above command, where the $4 represents the server number. Are you suggesting that quoting the $4 would be better or is there a better approach towards it. I am an amateur in shell, trying to automate what we do manually.
              – Raj
              Jul 18 at 8:22










            • I have doodled a bit at the end of my answer.
              – Kusalananda
              Jul 18 at 9:36















            If you had said something about how you were going to use the string, we would have found a solution for you much quicker. Note that this command would still give you false positives if the grep matches anything that isn't a filename in the ls output. Also, since $4 is unquoted, filename matching and word splitting will occur on its value. This is not the command you would want to use in a production system.
            – Kusalananda
            Jul 18 at 7:17




            If you had said something about how you were going to use the string, we would have found a solution for you much quicker. Note that this command would still give you false positives if the grep matches anything that isn't a filename in the ls output. Also, since $4 is unquoted, filename matching and word splitting will occur on its value. This is not the command you would want to use in a production system.
            – Kusalananda
            Jul 18 at 7:17












            @Kusalananda Thanks for the insight. As you understood, I want to get the latest file from the remote system for a provided server number. I am using the above command, where the $4 represents the server number. Are you suggesting that quoting the $4 would be better or is there a better approach towards it. I am an amateur in shell, trying to automate what we do manually.
            – Raj
            Jul 18 at 8:22




            @Kusalananda Thanks for the insight. As you understood, I want to get the latest file from the remote system for a provided server number. I am using the above command, where the $4 represents the server number. Are you suggesting that quoting the $4 would be better or is there a better approach towards it. I am an amateur in shell, trying to automate what we do manually.
            – Raj
            Jul 18 at 8:22












            I have doodled a bit at the end of my answer.
            – Kusalananda
            Jul 18 at 9:36




            I have doodled a bit at the end of my answer.
            – Kusalananda
            Jul 18 at 9:36










            up vote
            -2
            down vote













            Use single quote while storing the commands into variable. Use double quotes while using in echo command.



            $ cmd='ls -lrt /var/* /tmp/* /home/* | grep test | tail -1'
            $ echo "$cmd"
            ls -lrt /var/* /tmp/* /home/* | grep test | tail -1


            Difference between single and double quotes






            share|improve this answer























            • The double quotes used when assigning to cmd is not an issue here as the string doesn't contain anything that the shell would expand. Double quoting the expansion when printing the value is important though. It still doesn't explain why, on the user's system, it actually runs the command (which I haven't been able to replicate).
              – Kusalananda
              Jul 11 at 7:10










            • @Kamaraj , Thanks for the response. The single quote also doesn't seem to work. The expression in the quotes is being evaluated(I mean, the output we get when this command is executed on the command line) and stored in the variable.
              – Raj
              Jul 11 at 8:58














            up vote
            -2
            down vote













            Use single quote while storing the commands into variable. Use double quotes while using in echo command.



            $ cmd='ls -lrt /var/* /tmp/* /home/* | grep test | tail -1'
            $ echo "$cmd"
            ls -lrt /var/* /tmp/* /home/* | grep test | tail -1


            Difference between single and double quotes






            share|improve this answer























            • The double quotes used when assigning to cmd is not an issue here as the string doesn't contain anything that the shell would expand. Double quoting the expansion when printing the value is important though. It still doesn't explain why, on the user's system, it actually runs the command (which I haven't been able to replicate).
              – Kusalananda
              Jul 11 at 7:10










            • @Kamaraj , Thanks for the response. The single quote also doesn't seem to work. The expression in the quotes is being evaluated(I mean, the output we get when this command is executed on the command line) and stored in the variable.
              – Raj
              Jul 11 at 8:58












            up vote
            -2
            down vote










            up vote
            -2
            down vote









            Use single quote while storing the commands into variable. Use double quotes while using in echo command.



            $ cmd='ls -lrt /var/* /tmp/* /home/* | grep test | tail -1'
            $ echo "$cmd"
            ls -lrt /var/* /tmp/* /home/* | grep test | tail -1


            Difference between single and double quotes






            share|improve this answer















            Use single quote while storing the commands into variable. Use double quotes while using in echo command.



            $ cmd='ls -lrt /var/* /tmp/* /home/* | grep test | tail -1'
            $ echo "$cmd"
            ls -lrt /var/* /tmp/* /home/* | grep test | tail -1


            Difference between single and double quotes







            share|improve this answer















            share|improve this answer



            share|improve this answer








            edited Jul 11 at 9:11









            cezar

            11715




            11715











            answered Jul 11 at 6:55









            Kamaraj

            2,5341312




            2,5341312











            • The double quotes used when assigning to cmd is not an issue here as the string doesn't contain anything that the shell would expand. Double quoting the expansion when printing the value is important though. It still doesn't explain why, on the user's system, it actually runs the command (which I haven't been able to replicate).
              – Kusalananda
              Jul 11 at 7:10










            • @Kamaraj , Thanks for the response. The single quote also doesn't seem to work. The expression in the quotes is being evaluated(I mean, the output we get when this command is executed on the command line) and stored in the variable.
              – Raj
              Jul 11 at 8:58
















            • The double quotes used when assigning to cmd is not an issue here as the string doesn't contain anything that the shell would expand. Double quoting the expansion when printing the value is important though. It still doesn't explain why, on the user's system, it actually runs the command (which I haven't been able to replicate).
              – Kusalananda
              Jul 11 at 7:10










            • @Kamaraj , Thanks for the response. The single quote also doesn't seem to work. The expression in the quotes is being evaluated(I mean, the output we get when this command is executed on the command line) and stored in the variable.
              – Raj
              Jul 11 at 8:58















            The double quotes used when assigning to cmd is not an issue here as the string doesn't contain anything that the shell would expand. Double quoting the expansion when printing the value is important though. It still doesn't explain why, on the user's system, it actually runs the command (which I haven't been able to replicate).
            – Kusalananda
            Jul 11 at 7:10




            The double quotes used when assigning to cmd is not an issue here as the string doesn't contain anything that the shell would expand. Double quoting the expansion when printing the value is important though. It still doesn't explain why, on the user's system, it actually runs the command (which I haven't been able to replicate).
            – Kusalananda
            Jul 11 at 7:10












            @Kamaraj , Thanks for the response. The single quote also doesn't seem to work. The expression in the quotes is being evaluated(I mean, the output we get when this command is executed on the command line) and stored in the variable.
            – Raj
            Jul 11 at 8:58




            @Kamaraj , Thanks for the response. The single quote also doesn't seem to work. The expression in the quotes is being evaluated(I mean, the output we get when this command is executed on the command line) and stored in the variable.
            – Raj
            Jul 11 at 8:58


            Popular posts from this blog

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

            Bahrain

            Postfix configuration issue with fips on centos 7; mailgun relay