0

Based on this question,

How to delete directories based on `find` output?

I tried to remove only the first folder of result doing:

find * -type d | head -n1 | -exec rm -rf {} \;

But I receive this error:

bash: -exec: command not found

What's wrong?

  • -exec is a flag to find the | is a "pipe" between commands that connects the output of one command to the input of the next. So after the pipe is a separate command. – user1794469 Jan 21 '19 at 13:51
  • Similar recent confusion: https://unix.stackexchange.com/q/495361/117549 – Jeff Schaller Jan 21 '19 at 13:58

4 Answers4

4

You can use -quit after using -delete or -exec:

-quit
Exit immediately. No child processes will be left running, but no more paths specified on the command line will be processed.


Deleting the first result of your find command:

find * -type d -exec rm -Rf {} \; -quit

or

find . ! -path . -type d -exec rm -Rf {} \; -quit

The latter will find hidden folders.


Note, that your find output may not be sorted alphabetically.

For deletion of first result afer sorting:

find * -maxdepth 1 -type d -print0 | sort -z | head -zn1 | xargs -r0 rm -Rf

For numeric sort, use sort -zn.

pLumo
  • 22,565
0

pLumo has adequately given a few good alternative solutions in their answer. I'm providing a totally different approach.

You will notice that the find command, the way you're using it with * describing the top-level search paths, is only really used for finding the first directory among the names that * expands to.

You may do this with a shell loop too, which results in code that is easier to read and to see what it does:

shopt -s dotglob nullglob

for name in *; do if [ -d "$name" ] && [ ! -h "$name" ]; then rm -rf -- "$name" break fi done

This loop, which assumes it's running in a bash shell, iterates over all names matched by * (including hidden names). The body of the loop tests whether the current name is a directory (without being a symbolic link to a directory), and if so deletes the directory recursively before exiting the loop.

A similar effect could be had in the zsh shell with the much simpler command

rm -rf -- *(D/[1])

This removes the first directory that * expands to. The globbing qualifier (D/[1]) restricts the match of * to only directories (/), but includes hidden names (D), and returns only the first matching name ([1]). If there are no directories in the current directory, you would get a "no matches found" error message from the shell.

Kusalananda
  • 333,661
-1

This seems very dangerous but you could try:

find * -type d | head -n1 | xargs rm -rf
user1794469
  • 4,067
  • 1
  • 26
  • 42
  • 1
    Indeed dangerous. Having>$ ls: important_file important_file\nfake_folder, your command will delete very_important_file. Better use find -print0 and head -z and xargs -0. – pLumo Jan 21 '19 at 14:06
-1

for me worked this code:

  • finds ONLY the files with -type f,
  • filter files not containing ".gz"
  • select N files in this case ONLY FIRST ONE -n 1

code:

find . -type f ! -name "*.gz" | head -n 1 | xargs rm -rf {} ;

  • 1
    This seems to solve a different problem. Note that the user uses * as the search path. This means their find command will never (or should never) recurse into directories. – Kusalananda Jul 05 '21 at 10:02