3

I have the following files:

$ ls *.png | egrep -i "am|pm"
output-0 11.42.30 AM.png
output-0 5.10.12 PM.png
....

I want to remove them but get this error:

$ ls *.png | egrep -i "am|pm" | while read line; do rm "$line"; done
rm: cannot remove ''$'\033''[0m'$'\033''[01;35moutput-0 11.42.30 AM.png'$'\033''[0m': No such file or directory
rm: cannot remove ''$'\033''[01;35moutput-0 5.10.12 PM.png'$'\033''[0m': No such file or directory
rm: cannot remove ''$'\033''[01;35moutput-1 11.42.30 AM.png'$'\033''[0m': No such file or directory

What's the problem with my codes?

9

ls is risky in scripts and command lines. One problem is what is described in a comment by @PerlDuck, ANSI escape sequences for colour output. I would recommend another approach with find

  • Create test files

    touch 'output-0 11.42.30 AM.png' 'output-0 5.10.12 PM.png' asdf.png
    
  • Check that the findcommand line finds the files that you expect it to find

    find . -type f -iname "*[ap]m*.png"
    

    and do it

    find . -type f -iname "*[ap]m*.png" -delete
    

    If you don't want to search into subdirectories, add -maxdepth 1

    find . -maxdepth 1 -type f -iname "*[ap]m*.png" -delete
    
  • Check the result

    ls
    

    Files with am, pm, AM, PM in the name should be deleted but asdf.png is not deleted.

6

If you really want to use a while read loop in that way, then use a shell glob and printf with null delimiters e.g.

printf '%s\0' *.png | grep -zEi 'am|pm' | while IFS= read -r -d '' line; do echo "$line"; done

However, there are several ways to get bash to expand to a list of the files to be deleted directly - without the need to pipe to grep and while:

  1. using simple shell globs

    rm -- *[ap]m.png *[AP]M.png
    

    or - if you don't mind matching a .PNG extension as well - making use of the nocaseglob option

    shopt -s nocaseglob
    rm -- *[ap]m.png
    
  2. using extended globs

    shopt -s extglob
    rm -- *@(AM|PM).png *@(am|pm).png
    

or

    shopt -s extglob nocaseglob
    rm -- *@(am|pm).png

The -- marks the end of options, just in case there are filenames that begin with a hyphen - you can use a pattern with an explicit directory prefix like ./*(am|pm) instead if you prefer.

Add the -i or -I option if you want to review the file names interactively before deletion.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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