Echoing a tail command produces unexpected output?
Your crontab line has one or more asterisks *
in it, indicating "any time". When that line is substituted in from the command substitution, the result is something like
echo * * * * * cmd > /path/to/file
While most further expansions are not applied to the output of command substitution, pathname expansion is (as is field splitting):
The results of command substitution shall not be processed for further tilde expansion, parameter expansion, command substitution, or arithmetic expansion. If a command substitution occurs inside double-quotes, field splitting and pathname expansion shall not be performed on the results of the substitution.
Pathname expansion is what turns *.txt
into a list of matching filenames (globbing), where *
matches everything. The end result is that you get every (non-hidden) filename in the working directory listed for every *
in your crontab line.
You could fix this by quoting the expansion, if the code you posted was a representative of a more complex command:
sudo bash -c 'echo "$(tail -n 1 /etc/crontab)" > /path/to/file'
but more straightforwardly just lose the echo
entirely:
sudo bash -c 'tail -n 1 /etc/crontab > /path/to/file'
This should do what you want and it's simpler as well (the only other material difference is that this version will omit field splitting that would otherwise have occurred, so runs of spaces won't be collapsed).
Let's consider a directory with these files:
$ ls
crontab file1 file2 file3
$ cat crontab
f*
Now, let's run the tail command:
$ tail -n 1 crontab
f*
The above is the last line of crontab
and this is what we expect. However:
$ echo $(tail -n 1 crontab)
file1 file2 file3
Double-quotes eliminate this problem:
$ echo "$(tail -n 1 crontab)"
f*
Without the double-quotes, the result of the command substitution is expanded by the shell. One of the expansions is pathname expansion. In the case above, this means that f*
is expanded to match every file name that starts with f
.
Unless you explicitly want shell expansions, put all you shell variables and/or command substitutions inside double quotes.
globing shell mecanism will expand *
to local file.
crontab line is likely to have a *
as placeholder for any.
e.g. this line in crontab run on 7.47 am on sunday, first star mean any day, second any month.
47 7 * * 0 /run/on/sunday
then you tail
, and issue
echo 47 7 * * 0 /run/on/sunday
that will expand *
to local file.