0

i've found some inconsistency with bash commands and I wanted some clarification.

A comment mentioned here said Also, remember to quote the file pattern ".txt" or the shell will expand it.. But then why does the command

find . -name *.txt

Not obtain an error, it should be expanding the output using a wild card?

Also I found a nice page explaining the Differences in single quotes and double quotes,. but then why does using single quotes within a regex not break it? For example

find . -regex '.*x.txt'

Why does this work, and not look for the file literally called .*.txt

Cheersr

123
  • 1
  • This is off-topic because it is not about programming. – Jonathon Reinhart Jul 18 '18 at 03:20
  • However, note that if the shell wildcard pattern *doesn't* match anything, then it is passed as-is to the application. You need to think carefully about the difference between what s expanded by the shell, and what is handled by the application. Write a little utility that just prints it's arguments and experiment calling it with different things. – Jonathon Reinhart Jul 18 '18 at 03:21
  • When necessary. Once you know what quoting actually *does*, it's simple to figure out when it is and isn't necessary. – chepner Jul 18 '18 at 03:27
  • 2
    It can be about programming. Writing shell scripts is a form of programming. However, it is very broad. (Certainly the question in the title is ....) – Stephen C Jul 18 '18 at 04:05

1 Answers1

2

The shell expands unquoted patterns (where a pattern is a word containing a pattern metacharacter like *) before calling the command contained in a command line. In this case, find . -name *.txt expands to, perhaps, find . -name a.txt b.txt c.txt, in which case only a.txt is the argument to the -name primary of the find command. To prevent this expansion, you quote *.txt, because you want that literal string to be the argument.

find . -name '*.txt'

find itself uses the pattern to match against each file found while recursing the current directory.

bash lets you be somewhat lazy, because if *.txt doesn't actually match anything, then it is treated as a literal string by default. There are shell options that change this behavior: nullglob causes an unmatched pattern to simply disappear, as if it never existed, and failglob causes the shell to raise an error instead. However, it's best to be explicit: if you don't intend a string to undergo pathname expansion, quote it to ensure that it cannot be expanded.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • i;m just reading the single vote vs double quote in my link from before. In his example, #11 he says globing doesn't work in quoted strings of any type. Then why does it work in literally every script people write such as '*.txt'? – 123 Jul 18 '18 at 04:36
  • @123: *globbing doesn't work in quoted strings* is correct, **in the shell**. But `find` is not part of the shell, it is an external program with its own globbing system. Passing `find` a parameter of `'*.txt'` has to be quoted because it is parsed by the shell *before* the external `find` program is called. If it was not protected then the shell would leap in and expand it before `find` was even started. – cdarke Jul 18 '18 at 06:47
  • @cdarke Interesting, how do I differentiate the difference between an internal or external program. Are internals programs just scripts we make ourselves and external programs the one that come precompiled in the os? – 123 Jul 18 '18 at 08:47
  • No, internal commands are those that are implemented by the shell itself. Some cannot be implemented as external commands (like `cd`, which changes the state of the shell), while others could be implemented as either (like `test`, which exists as both; the internal version is more efficient because it doesn't require a new process to be forked). The shell's documentation (e.g. the man page) will list the supported built-in internal commands. – chepner Jul 18 '18 at 12:19
  • 1
    As @chepner says, but a simple way to discover if a command is built-in or external is to use the `type` command. Try `type cd`, `type echo`, `type ls`, `type find`, `type [[`. If you get `hashed`, that means it is an external program where the path is cached. – cdarke Jul 18 '18 at 12:30