12

I use CentOS shared server environment with Bash.

ll "$HOME"/public_html/cron_daily/

brings:

./
../
-rwxr-xr-x 1 user group 181 Jul 11 11:32 wp_cli.sh*

I don't know why the filename has an asterisk in the end. I don't recall adding it and when I tried to change it I got this output:

[~/public_html]# mv cron_daily/wp_cli.sh* cron_daily/wp_cli.sh
+ mv cron_daily/wp_cli.sh cron_daily/wp_cli.sh
mv: `cron_daily/wp_cli.sh' and `cron_daily/wp_cli.sh' are the same file

This error might indicate why my Cpanel cronjob failed:

enter image description here

Did I do anything wrong when changing the file or when running the Cpanel cron command? Because both operations seem to fail.

3
  • I don't know if this can happen on Linux, but I recall a few cases on, I'm thinking, UNIX and MSDOS, where such "illegal" names had actually been created, presumably as a result of using a machine-language interface to manipulate/rename files, vs using the normal command and HL language interfaces.
    – Hot Licks
    Jul 15, 2018 at 1:57
  • 1
    @HotLicks The only illegal names (at least on Linux) are an empty string, and a name with a slash (/) or null byte. You can make files with asterisks no-prob by quoting the asterisk or escaping it like this touch wp_cli.sh\*.
    – JoL
    Jul 15, 2018 at 19:06
  • Similar: superuser.com/questions/178786/…
    – mgutt
    Aug 1, 2019 at 1:24

2 Answers 2

32

The asterisk is not actually part of the filename. You are seeing it because the file is executable and your alias for ll includes the -F flag:

-F

Display a slash ('/') immediately after each pathname that is a directory, an asterisk ('*') after each that is executable, an at sign ('@') after each symbolic link, an equals sign (`=') after each socket, a percent sign ('%') after each whiteout, and a vertical bar ('|') after each that is a FIFO.


As Kusalananda mentioned you can't glob all scripts in a directory with cron like that. With run-parts, you can call "$HOME"/public_html/cron_daily/ to execute all scripts in the directory (not just .sh) or loop through them as mentioned in this post.

4
  • 2
    Additionally, the cronjob fails because you can't execute all script in a directory like that. See unix.stackexchange.com/questions/454749/…
    – Kusalananda
    Jul 14, 2018 at 17:28
  • Uh, how would "$HOME"/public_html/cron_daily/ run all scripts in the directory? cron will only run one command, and it won't use shell expansion. The easiest solution for OP would be to create a wrapper script that does for script in "$HOME"/public_html/cron_daily/*.sh; do $script; done, and then call the wrapper from cron.
    – nneonneo
    Jul 15, 2018 at 1:36
  • @nneonneo Debian/Ubuntu already have run-parts, which does this, maybe other distributions have something similar? Jul 15, 2018 at 9:54
  • @nneonneo: Updated
    – jesse_b
    Jul 15, 2018 at 11:05
11

Jesse_b already answered the question, but I think it's worth to address some potential misconceptions.

The shell has characters that have special meaning under some specific conditions. For example: | is used in pipelines, > in redirections, \ to escape characters, etc. Those characters are not interpreted literally by the shell, so that's why when you do echo foo>bar, foo>bar won't be printed to your terminal, but foo will be redirected to the bar file.

Fortunately, the shell also has a mechanism which makes these characters to lose their special meaning: quoting. In POSIX shells, there are 3 quoting mechanisms:

  • Backslash \: preserves the literal value of the following character, with the exception of a <newline>.
  • Double-quotes "...": preserves the literal value of all characters within the double-quotes, with the exception of the characters `, $, and \.
  • Single-quotes '...': preserves the literal value of each character within the single-quotes, no exceptions.

So, following the previous example, if we wanted to print foo>bar literally, we could have done:

  • echo foo\>bar
  • echo "foo>bar"
  • echo 'foo>bar'

The asterisk * is one of those special characters, it is part of the pattern matching notation and is used for filename expansion. In other words, commands such as echo *.txt will replace the pattern with the files that the pattern matches.

In your case, cron_daily/wp_cli.sh* only matches cron_daily/wp_cli.sh, so mv sees 2 identical arguments and complains about it. That's fine because there's no cron_daily/wp_cli.sh* file. But if you had had an actual cron_daily/wp_cli.sh* file and more files that could be matched by the pattern, mv would have fail.

Consider the following scenario:

$ ls -l
total 0
-rw-rw-r-- 1 user group 0 jul 14 12:00 file*
-rw-rw-r-- 1 user group 0 jul 14 12:00 file1
-rw-rw-r-- 1 user group 0 jul 14 12:00 file2
-rw-rw-r-- 1 user group 0 jul 14 12:00 file3

If I try to rename file* without using quotes:

$ mv file* new_file
mv: target 'new_file' is not a directory

That's because these are the arguments that mv receives, thus new_file is expected to be a directory:

$ printf '[%s]\n' file* new_file
[file*]
[file1]
[file2]
[file3]
[new_file]

To successfully rename file*, I need to quote that argument:

$ mv 'file*' new_file
$ ls -l
total 0
-rw-rw-r-- 1 user group 0 jul 14 12:00 file1
-rw-rw-r-- 1 user group 0 jul 14 12:00 file2
-rw-rw-r-- 1 user group 0 jul 14 12:00 file3
-rw-rw-r-- 1 user group 0 jul 14 12:00 new_file

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .