13

I'm wondering about direction of recursion in general and rm specifically.

rm recursion only works downwards correct?

Running: sudo rm -R *.QTFS will delete all *.QTFS files in current directory and its children, correct?

current directory as displayed by ls -lha also contains . and .. links for the lack of a better word, so why doesn't recursion follow these upwards in the directory tree? Is there an artificial limit on rm app, or . and .. are not real things?

  • 5
    Because root, and madness, that way lies... – jasonwryan Sep 02 '14 at 05:08
  • 2
    Related: [Does 'rm .*' ever delete the parent directory?](http://unix.stackexchange.com/q/90073/22565) – Stéphane Chazelas Sep 02 '14 at 06:35
  • 1
    Well, for an interesting anecdote... I ran rm -rf on some innocent looking subdirectories at one point only to find to my horror that a user had hard linked stuff in there to a very important upstream, which rm then proceeded to eat. Yeah, I had current backups and no data was lost, but let it be a cautionary tale... :-) – Brian Knoblauch Sep 02 '14 at 15:20
  • @BrianKnoblauch, what harm could be done by removing a hard link? I didn't get the point of you story... – Alexey Nov 01 '19 at 17:32
  • @Alexey The point is that the hard link itself was not removed. It recursed down into the hard linked directory, which was linked to a higher point in the filesystem, so started eating everyone's data... – Brian Knoblauch Nov 01 '19 at 17:37
  • @BrianKnoblauch, but i do not believe someone could [hardlink a directory](https://unix.stackexchange.com/q/22394). – Alexey Nov 01 '19 at 19:16
  • @Alexey That particular version of Solaris definitely did allow it. I know. I had to recover the data that got wiped out... – Brian Knoblauch Nov 01 '19 at 19:50
  • I understand now, thanks. – Alexey Nov 01 '19 at 20:24

2 Answers2

18

rm recursion only works downwards correct?

rm -r x y will delete x and y and everything inside them (if they are directories), but not their parents or anything outside them.

Running: sudo rm -R *.QTFS will delete all *.QTFS files in current directory and its children, correct?

No. It will delete all files named *.QTFS, any files recursively inside directories called *.QTFS, and those directories themselves. If you want that other deletion behaviour, use find -delete.

current directory as displayed by ls -lha also contains . and .. links for the lack of a better word, so why doesn't recursion follow these upwards in the directory tree? Is there an artificial limit on rm app, or . and .. are not real things?

It's an artificial limit of rm.

It's not really all that artificial, though - it's the only way it could ever work. If rm followed the parent .. links, every rm -r would remove every file on the system, by following all of the .. links all the way back to /. rm sees the .. and . entries in each directory when it lists the content, and explicitly disregards them for that reason.

You can try that out yourself, in fact. Run rm -r . and most rm implementations will refuse to act, reporting an error explicitly:

$ rm -r .
rm: refusing to remove ‘.’ or ‘..’ directory: skipping ‘.’

(that message is from GNU rm; others are similar). When it encounters these entries implicitly, rather than as explicit arguments, it just ignores them and continues on. That behaviour is required by POSIX. In GNU rm and many of the BSDs, it's provided automatically by the fts_read family of hierarchy-traversal functions.

or . and .. are not real things?

. and .. are generally real directory entries, although that is filesystem-specific. They will almost always be presented as though they are real entries to all user code, regardless. Many pieces of software (not just rm) special-case their behaviour in order to catch or prevent runaway or undesirable recursion.

Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
Michael Homer
  • 74,824
  • 17
  • 212
  • 233
  • For anyone seeking proof (or just plain interested), take a look at [how this is implemented in GNU coreutils](http://lingrok.org/xref/coreutils/src/remove.c#438). – Chris Hayes Sep 02 '14 at 08:18
  • @ChrisHayes The equivalent gitweb link is in the answer. The actual recursive case is in the `fts_read` implementation, though, that one is just for command-line arguments. – Michael Homer Sep 02 '14 at 08:26
  • @MichaelHomer Oh wow, so it is. That link color does *not* stand out on this SE scheme. My mistake. – Chris Hayes Sep 02 '14 at 08:41
  • 2
    This answer is correct but also a little imprecise. `rm` doesn't even see `*.QTFS` because it's glob-expanded into the filenames by bash before the rm binary is invoked. @tobyink's answer notes that. – Daenyth Sep 02 '14 at 15:43
  • As a sidenote, those `.` and `..` special-case behaviour are said to be [the cause of the dotfiles existence](https://plus.google.com/+RobPikeTheHuman/posts/R58WgWwN9jp) – mgarciaisaia Sep 02 '14 at 17:03
  • Be carefull here. Some older UNIX systems (some early bsd's, Ultrix) will go upstream if you do "rm -rf .*". Told a colleague of mine that back in the 90's and he wouldn't believe me. Lucky for him it was a decommissioned system that was going to be scrapped anyway. – Tonny Sep 02 '14 at 18:42
5

As well as what Michael Homer wrote there's another factor that makes it hard to accidentally recurse into the parent directory.

Go into your home directory and type something like:

echo *s*

You'll see that it shows a list of files and directories containing the letter "s". However, no files beginning with a leading dot are shown. To show them, you can use:

echo .*s*

This is because the shell refuses to expand * to encompass a leading dot. This means that:

rm -fr *

Will not recurse into ...

tobyink
  • 151
  • 3