tags:

views:

425

answers:

4

Hy, suppose you got many files in a folder and you want first to sort it in alphabetic order and then delete all files until a specific file (not including it).

So im searching for a function/command/script/whatever which takes one string as imput and the deletes all files until this file.

I thought of a simple bash-script:

for i in *; do
   if [ "$i" == "input" ]; then
      break;
   fi
   rm "$i"
 done

but this is a quite long solution, and it doesnt work as wanted because the sorting is not specified. Isn't there a shorter one?

Thanks

A: 

If you want sorting:

for i in `ls | sort`
do
    if [ "$i" == "input" ]
    then
        break
    fi
    rm "$i"
done

Certainly, this could be made shorter, but this solution is probably the simplest and most readable (which usually matters the most). And this does handle files with spaces correctly now.

Zifre
Leads into errors if filenames contains spaces. I know this can be fixed by a "ls | sort | while read line;" but it makes the code even longer. Thanks anyway!
theomega
Oh yeah, I forgot about the spaces problem... if you add the quotes, it works though (at least on my machine).
Zifre
Pathname expansion with * is already sorted. "***And don't parse ls.***"
Dennis Williamson
+1  A: 

This seems to work ($i being the filename up to which to delete)

find . -maxdepth 1 -type f | sort | 
    while read -r line && [[ $line < $i ]]; do 
        echo $line
    done

If you are sure it does what you want, replace the echo command by

rm "$line"

Never pipe ls for processing things. ls isn't made for that task. Use pathname expansion or tools like find.

Example failure case:

$ echo > 'I have fun.mp3'
$ cat $(ls | grep 'have fun')
cat: I: No such file or directory
cat: have: No such file or directory
cat: fun.mp3: No such file or directory

It splits the result of $(...) into words and passes these words as separate arguments. Thus, rm would not see such a name as a whole, but as splitted into its words.

Pathname expansion is done after word splitting, so word splitting does not affect its result anymore. That is why a cat * will correctly handle spaces (or for that purpose, any other characters in the IFS variable).

Johannes Schaub - litb
+2  A: 

Try,

rm $(ls | sort | sed '/input/,$d')

First try this without the rm as,

ls | sort | sed '/input/,$d'

Here, input is your regex to catch the filename. Remember, everything after the first match will go!

nik
+1 That solution is and short AND readable.
Zifre
... if you understand sed
Zifre
Would you mind explaining the sed command, please?
Rob Kennedy
piping ls will cause problems with escape characters and word splitting. (this won't work with spaces in filenames, i think)
Johannes Schaub - litb
IT worked with a space separated filename for me.
nik
#Rob, the ls and sort are obvious, the sed searches for input regex and starting from the first line that matches (,) deletes (d) up to the end of file ($). What remains reaches stdout.
nik
+2  A: 
rm `ls |sed '/pattern/,$d'`

ls output is sorted alphabetically by default.

Replace pattern with a regular expression that matches the first file past the one to delete. Unless there's anything fancy going on, pattern can be just the name of the file to stop deleting on. Or use "^filename$" for pattern to be certain.

As always, test before doing. For example, add "echo" at the start to just print what would be done.

echo rm `ls |sed '/pattern/,$d'`
John M
Never, ever, ever parse ls: http://mywiki.wooledge.org/ParsingLs
Dennis Williamson
Interesting article about parsing ls output. Take that into account if you've got a chance of such crazy filenames or need security in the face of untrustworthy inputs (directory contents). Seems like tough advice to live with in general.
John M
If you want to replace the `ls` to get a list of files (i guess you would want to skip directory names for `rm`). Use, `find . -type f`.
nik
How would that relate to the "never ever parse" point? It'd apply to find output too, no? Seems like find is scratching a different itch -- desire for recursion vs just current dir.
John M
@John M: The output of `find` is reliable and intended to be parsed. The output of `ls` is "eyes only". Read the page I referenced in my comment above.
Dennis Williamson