16

Let's say I have two files in /tmp:

root@ubuntu:~# touch /tmp/hello.{pyc,py}

root@ubuntu:~# ls /tmp/
hello.py  hello.pyc

Now, lets run rm -rf command with [co] option

root@ubuntu:~# rm -rf /tmp/hello.py[co]

root@ubuntu:~# ls /tmp/
hello.py

Can someone please explain what's happening here? What is the [co] parameter? How can we make it work for other extensions? Say I have foo.js and foo.coffee files, can we do something like rm -rf /tmp/foo.coffe[co] to delete the /tmp/foo.js?

  • 8
    There's no need for -rf there, as those are neither directories (--recursive), nor unwritable (--force). – deltab Jul 20 '16 at 14:15
  • 13
    There's no need for -rf and there's no need to be doing things as root. Especially if the things in question involve rm -rf. – terdon Jul 20 '16 at 15:34
  • Guys, its just sample commands to explain the problem. The actual question was about [co] shell glob. Thanks. – aneeshep Jul 20 '16 at 22:28
  • 8
    @aneeshep If someone's looking down the barrel of a gun and asking how to clean it, do you first warn them about looking down the barrel or tell them how to clean it? – Duncan X Simpson Jul 21 '16 at 2:02
34

[co] isn't a parameter to the rm command - it's a shell glob that matches a pattern equal to a single character from the set [co] - in other words, it matches either a c or an o a the end of the filename. From man bash:

[...]  Matches any one of the enclosed characters

To match both foo.coffee and foo.js, since the suffixes don't contain any common substrings at all, the best you could do is foo.* which would match any filename starting with foo. Instead you could use brace expansion e.g.

rm foo.{coffee,js}
  • Yup got it. I missed the basic concept in bash ;). Thank you :) – aneeshep Jul 20 '16 at 10:30
  • 7
    search patterns like [abc] or * will search for files while {} won't. go to /tmp, type echo nya[ab]; echo nya{a,b}, then touch nyaa and again echo nya[ab]; echo nya{a,b} – Sanya_Zol Jul 20 '16 at 17:17
16

It is not a parameter but a collection of letters (or a "shell glob"). This is the same:

rm -rf /tmp/hello.py[co]

is the same as

rm -rf /tmp/hello.pyc
rm -rf /tmp/hello.pyo

Similar ...

rm -rf /tmp/hello.py[c-o]

would delete anything from /tmp/hello.pyc up to and including /tmp/hello.pyo following ASCII ordering.

rm -rf /tmp/hello.py[ab][cd]

would remove ...

rm -rf /tmp/hello.pyac
rm -rf /tmp/hello.pyad
rm -rf /tmp/hello.pybc
rm -rf /tmp/hello.pybd

say, i have foo.js and foo.coffee files, can we do something like rm -rf /tmp/foo.coffe[co] to delete the /tmp/foo.js.

You can make rather fancy methods but for those 2 files I'd just remove them with 1 command for each. Another example getting as close as possible to those 2 files...

rm /tmp/foo.[cj]*

would remove files like this ...

rm /tmp/foo.c*
rm /tmp/foo.j*

so it would include far more than just these 2 files.

  • 2
    If I am not misunderstanding, you get one invocation of rm -rf with all of the matches, not many invocations each with one match. – user378002 Jul 20 '16 at 16:33
  • 1
    yes. but not the intent of the rm's i added. those are just to show what would be needed to be typed as an equivalent ;-) – Rinzwind Jul 20 '16 at 18:12
1

It's a shell glob, similar to wildcards * and ? ...in bash, the filename pattern *.[co] matches all filenames that finish with .c or .o.

The difference with *.[co] versus *.c *.o or *.{c,o} is that the two latter patterns will expand to a dummy *.o if no .o files exist in the directory, while the *.[co] version won't.

Shell globs are useful for doing file operations in a non-case-sensitive way. For example, if you have a bunch of files with filenames that end with jpg, JPG, Jpg, JPg, etc... and you want to remove all of them, you can do:

rm *.[Jj][Pp][Gg]

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.