They way wilcard expansion is done in 'ls *' depends on the number of files in the current directory. If there are two or more files/subdirs in the current directory, 'ls *' produces the list of current directory (this is ok). But if there is only one subdirectory in the current directory, 'ls *' also produces the list of files in this subdirectory. This is inconsistent approach to my mind. Steps to reproduce: $ touch file1 file2 $ sftp user@host Connected to host. Changing to: /home/user/ sftp> mkdir test sftp> cd test sftp> mkdir dir1 sftp> mkdir dir2 sftp> put file* dir1 Uploading file1 to /home/user/test/dir1/file1 Uploading file2 to /home/user/test/dir1/file2 sftp> ls -1 * dir1/ dir2/ Note the result of the above command. Assume this is a correct behaviour. Now we'll remove dir2 and see how 'ls -1 *' output changes. I expect to see only 'dir1/' in the output. sftp> rmdir dir2 sftp> ls -1 * dir1/file1 dir1/file2 sftp> We can see that the output is quite different from our expectations. It showed 'dir1/file1 dir1/file2' instead of 'dir1/'. This bug appeared in somewhere around OpenSSH_4.2p1, maybe a little bit earlier. It is still present in OpenSSH_5.5p1-snap20100505. This bug does NOT present in OpenSSH_3.8.1p1.
This is the special case code: 755 /* 756 * If the glob returns a single match and it is a directory, 757 * then just list its contents. 758 */ 759 if (g.gl_matchc == 1) { 760 if ((a = do_lstat(conn, g.gl_pathv[0], 1)) == NULL) { 761 globfree(&g); 762 return (-1); 763 } 764 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 765 S_ISDIR(a->perm)) { 766 int err; 767 768 err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag); 769 globfree(&g); 770 return (err); 771 } 772 } Arguably, the special case behaviour is more consistent with a normal shell when executing "ls *"
This behaviour is confusing for scripts that invoke sftp in batch mode. "ls -1 *" is a convenient way for a script to differ directories from files because directories are marked by '/' in the end of them.