Store command in a variable without evaluation - Unix [closed]
Clash 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?
linux bash shell-script shell scripting
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.
 |Â
show 10 more comments
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?
linux bash shell-script shell scripting
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 withbash
. 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. Usingprintf '%sn' "$cmd"
would prevent that (or evenecho "$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 finaltail -1
incmd
?
â Kusalananda
Jul 11 at 7:12
1
@Raj Thebash
shell just does not do that.
â Kusalananda
Jul 11 at 8:50
 |Â
show 10 more comments
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?
linux bash shell-script shell scripting
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?
linux bash shell-script shell scripting
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 withbash
. 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. Usingprintf '%sn' "$cmd"
would prevent that (or evenecho "$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 finaltail -1
incmd
?
â Kusalananda
Jul 11 at 7:12
1
@Raj Thebash
shell just does not do that.
â Kusalananda
Jul 11 at 8:50
 |Â
show 10 more comments
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 withbash
. 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. Usingprintf '%sn' "$cmd"
would prevent that (or evenecho "$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 finaltail -1
incmd
?
â Kusalananda
Jul 11 at 7:12
1
@Raj Thebash
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
 |Â
show 10 more comments
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
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 contain299
?
â 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
add a comment |Â
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
add a comment |Â
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"
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 thegrep
matches anything that isn't a filename in thels
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
add a comment |Â
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
The double quotes used when assigning tocmd
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
add a comment |Â
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
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 contain299
?
â 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
add a comment |Â
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
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 contain299
?
â 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
add a comment |Â
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
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
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 contain299
?
â 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
add a comment |Â
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 contain299
?
â 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
add a comment |Â
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
add a comment |Â
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
add a comment |Â
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
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
edited Jul 11 at 10:56
answered Jul 11 at 10:51
alux
364
364
add a comment |Â
add a comment |Â
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"
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 thegrep
matches anything that isn't a filename in thels
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
add a comment |Â
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"
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 thegrep
matches anything that isn't a filename in thels
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
add a comment |Â
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"
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"
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 thegrep
matches anything that isn't a filename in thels
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
add a comment |Â
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 thegrep
matches anything that isn't a filename in thels
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
add a comment |Â
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
The double quotes used when assigning tocmd
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
add a comment |Â
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
The double quotes used when assigning tocmd
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
add a comment |Â
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
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
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 tocmd
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
add a comment |Â
The double quotes used when assigning tocmd
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
add a comment |Â
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. Usingprintf '%sn' "$cmd"
would prevent that (or evenecho "$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
incmd
?â Kusalananda
Jul 11 at 7:12
1
@Raj The
bash
shell just does not do that.â Kusalananda
Jul 11 at 8:50