What do double-asterisk wildcards mean?

2019-01-17 10:01发布

问题:

I've tried the following command but I am having trouble interpreting it:

ls **

but I'm not sure exactly what it is outputting and why that is the result.

回答1:

Consider the following directory tree:

folderA
├── file1
├── file2
└── folderB
    ├── file3
    └── folderC

ls will list all objects in the current folder:

$ ls
file1  file2  folderB

ls * will list all objects in the current folder and in addition one more level recursively

$ ls *
file1  file2 

folderB:
file3  folderC

Keith's answer is the correct one. Refer there.



回答2:

It's probably using a special feature of some shells that lets ** do a recursive match, as opposed to a single *, which matches only in the current directory.

The wildcard * matches any file or directory (whose name doesn't start with .) in the current directory.

Depending on which shell you're using, and with which settings, ** may be equivalent to *; it could match zero or more characters followed by zero or more characters, which is the same as matching zero or more characters just once.

But with some shells, with some settings, ** is a recursive version of *, matching all files and directories in the current directory and subdirectories.

Quoting the bash manual:

`*'
Matches any string, including the null string. When the `globstar' shell option is enabled, and `*' is used in a filename expansion context, two adjacent `*'s used as a single pattern will match all files and zero or more directories and subdirectories. If followed by a `/', two adjacent ``*'s will match only directories and subdirectories.

This works only if the globstar option is set via:

shopt -s globstar

(it's disabled by default) and only in relatively recent versions of bash.

I believe zsh also supports this syntax.

It's important to keep in mind that wildcards are expanded by the shell, not by the ls command. If you type ls **, or ls *.txt, the ls command itself never sees the * characters; it only sees an expanded list of files, just as if you had typed the entire list on the command line.



回答3:

The exact behavior of this particular wildcard has been well covered by the other answers, but information on the general case may be useful.

This behavior is not limited to ls, and is referred to as "globbing", which is the expansion of patterns based on matches with existing filenames. It is important to note that these patterns do not use regular expression syntax.

The shell pre-processes the arguments before they are sent to the program. There are generally multiple levels of expansion, some of these involve globbing.

A great resource for more information on the other wildcards available in a file glob pattern is the unix manpage. A online version for glob can be found here.

Finally, a simple example of what this can do for you, especially when combined with other shell expansion goodies, in this case those provided by the bash shell. Information about the expansions used in this example can be found in the Bash Guide for Beginners - which is my goto resource, despite the title.

ls *{01..04}.{txt,csv} becomes ls *01.txt *01.csv *02.txt *02.csv *03.txt *03.csv *04.txt *04.csv

Which could output something like this:

input_01.txt input_02.txt input_03.txt input_04.txt output_01.csv output_02.csv output_03.csv output_04.csv

While skipping these:

input_05.txt input_06.txt input_07.txt input_08.txt input_09.txt input_10.txt output_05.csv output_06.csv output_07.csv output_08.csv output_09.csv output_10.csv

A trivial example, but if you know that this behavior is not specific to ls, then you can imagine the utility when coupled with mv, cp, rsync, etc.



回答4:

Similar to the DOS dir command, the function of the ls command is to list files and directories. When the thing to be listed is a file, the command simply lists the file, no big deal. When the thing to be listed is a folder, the command lists the contents of the folder. Also, if you just the the ls command with no arguments, the default thing to list is the working directory, or current folder. (Also, the current folder's name is always ., so the bare ls command is equivalent to ls ..)

Example: You have in your current folder a file named file_001, a folder named folder_002, and in the folder you have files named picture_003 and picture_004. When you type ls, you will see file_001 folder_002, and when you type ls folder_002, you will see picture_003 picture_004.

In Unix, wildcard processing is performed by the shell. When you type ls **, your shell processes the **, before it runs the ls command, it replaces the ** with the names of all the files/folders that matched. (The * wildcard matches any file or folder. Using ** matches any file or folder whose name begins with anything and ends with anything, so it's functionally equivalent to just *.)

In this case, when the ls command gets run, the command line arguments are a list of all the files and folders in the current folder, just as though you had typed them all out yourself. So in our example, you are now running the command ls file_001 folder_002. When the ls command processes its command line, the first item is a file, so it simply lists the file, and the second item is a folder, so it lists the contents of the folder. Additionally, since the command is listing more than one thing, it prints a label with the folder's name, so you can differentiate the folder's content in the output listing from whatever else is also being listed. As a result, the output of the command ls ** will look like this:

file_001

folder_002:
picture_003   picture_004`

I'm curious, though. What guide, book, or document suggested that you try the command ls **?



标签: unix wildcard