How to delete all files with filenames containing spaces on Linux? [duplicate]
I managed to delete everything myself using vi to edit the temporary file, after discovering that there were also filenames which contained parenthesis — which the shell also does not like.
2 Answers 2
Alright, let’s do this progressively.
And let’s presume that you really do want to look in subdirectories as well, even though that’s only implied in your question.
As a first pass, this is just a simple exercise in passing a wildcard to the find command, remembering to quote it of course, and executing the rm command for every file found:
find $BASE_DIR/ -name '* *' -exec rm <> \;
But of course that’s dreadfully inefficient. It starts up a whole rm process for each individual file. So while we could take a short detour through \+ that’s not where we are going to end up, so let’s take the shorter route and bring in xargs to batch up the filenames into groups:
find $BASE_DIR/ -name '* *' -print | xargs rm
But that has two security holes. First, if any filename found happens to begin with a minus sign rm will treat it as a command-line option rather than a filename, and generate an error. (The -exec rm <> version also has this problem.) Second, filenames containing whitespace will not be handled properly by xargs , as you’ve noticed. So a further iteration is to make this a little more bulletproof:
find $BASE_DIR/ -name '* *' -print0 | xargs -0 rm --
And, of course, there are the interactive features of rm that you probably don’t want:
find $BASE_DIR/ -name '* *' -print0 | xargs -0 rm -f --
The -print0 and -0 options are not standard, but the GNU find and xargs , as well as the FreeBSD find and xargs , understand them. However, even this is improvable. We don’t need to spawn any extra processes at all. The GNU and FreeBSD find s can both invoke the unlink(2) system call directly:
find $BASE_DIR/ -name '* *' -delete
As a last preventative measure to stop you doing more than you intended in certain circumstances, remember that the filesystem can contain more than just regular files:
find $BASE_DIR/ -name '* *' -type f -delete
remove file starting with space in shell scripting
I’m trying to write a shell script to cleanup a directory by deleting files that match particular patterns. My code works with all patterns but if the file name starts with space. Although we can delete a file starting with space by rm \ * however if I pass this pattern to my script it won’t delete files starting with space. Here is my code:
for file in *;do for pattern in $*; do if [[ -f "$file" && "$file" == $pattern ]]; then rm "$file" fi done done
for pattern in $*; do if [[ -f $pattern ]]; then rm $pattern fi done
problem is with $* when we assign value to variable like a=» dsdsd» and echo $a then it will print «dsdsd» without space. While assigning value to varible space is lost.
But the problem is that I need to receive the pattern from command line. My script should be called this way: ./dirclean.sh ~/dirname «PATERN1» «PATERN2″ . . So I have to use a variable instead of » «* in your suggested code. In addition, PATTERN could be anything else as well, but I noticed this problem while testing my code with files starting with space.
3 Answers 3
Rather than $* , if you use the special parameter $@ , the items in the list will start with quotes around them. You still have to quote the variables where you use them.
Reworking the second example, that would be
for pattern in "$@"; do if [[ -f "$pattern" ]]; then rm -f "$pattern" fi done
I changed the code, But it doesn’t delete files starting with space. My Script file name is dirclean ad I run it as follow: ./dirclean.sh ~/mydir «\ *» . This result in deletion of all files in mydir.
This time it’s not working with any other patterns as well because when $@ is quoted, it would be considered as a string. This only can delete files with the name of $@
It sounds as if on applying the suggested changes, your resulting script has either single-quoted something, or escaped something. The reworked second example was able to work as expected with a plain * (no quotes) for a parameter. bash (not mentioned in the question) does have a way to match against a pattern. You might want to start a new question to focus on that aspect.
this is really a challenging one for starters please see below example
[shravan@localhost mydir]$ ls " myfile" myfile [shravan@localhost mydir]$ echo $vr1 " myfile" [shravan@localhost mydir]$ ls $vr1 ls: ": No such file or directory ls: myfile": No such file or directory [shravan@localhost mydir]$ vr2=" myfile" [shravan@localhost mydir]$ echo $vr2 myfile
You can see above that ls » myfile» is working but it is not working after assigning this value in variable vr1 or vr2. So we cannot do check of file if it exists or not.
For solution keep all you patterns in a file and all patterns in double quotes. see example below.
[shravan@localhost mydir]$ touch " myfile" [shravan@localhost mydir]$ touch my.pl [shravan@localhost mydir]$ ls exe.sh findrm inp input myfile my.pl pattern text text1 [shravan@localhost mydir]$ cat inp " myfile" "my.pl" [shravan@localhost mydir]$ cat inp | xargs rm [shravan@localhost mydir]$ ls exe.sh findrm inp input pattern text text1
The files are removed. Or if you have lot of patterns and dont want to add quotes to them use below.
Yes if file is not found then it will give error for that file that
rm: cannot remove ` myfile': No such file or directory
Deleting files with spaces in their names
I am trying to delete all the files with a space in their names. I am using following command. But it is giving me an error Command : ls | egrep ‘. ‘ | xargs rm Here if I am using only ls | egrep ‘. ‘ command it is giving me all the file name with spaces in the filenames. But when I am trying to pass the output to rm, all the spaces (leading or trailing) gets deleted. So my command is not getting properly executed. Any pointers on how to delete the file having atleast one space in their name?
6 Answers 6
You can use standard globbing on the rm command:
This will delete any file whose name contains a space; the space is escaped so the shell doesn’t interpret it as a separator. Adding — will avoid problems with filenames starting with dashes (they won’t be interpreted as arguments by rm ).
If you want to confirm each file before it’s deleted, add the -i option:
You will DEFINITELY want to run this through an echo first, to guard from typos. Add echo at the front and it will print out all the files it’s going to remove.
Anuj, the reason why this has the most upvotes is that because though find is powerful, sometimes you don’t need to kill the chicken with a machine gun. UNIX administrators would generally not resort to find to (for example) «remove all files beginning with the letter A». one would simply rm A* . Likewise to remove files containing spaces, rm can do the job. In other words, don’t be fooled because space is invisible and is treated specially by the shell. Simply escape it, as Stephen Kitt has done, and you can think of it like any other character.
I would avoid parsing ls output
find . -type f -name '* *' -delete
Although this is recursive and will delete all files with space in current directory and nested directories, as mentionned in comments.
(1) you can use -name ‘* *’ instead of the regex; and (2) you can use -print0 | xargs -0 rm -i to address @StephenKitt’s concern.
Look at this Suppose name «strange file»
find . -inum "numberoofinode" -exec rm <> \;
In case of very strange file names like
xargs reads items from the standard input, delimited by blanks (which can be protected with double or single quotes or a backslash) or newlines, and executes the command (default is /bin/echo) one or more times with any initial-arguments followed by items read from standard input. Blank lines on the standard input are ignored.
We can (mostly) fix your initial command by changing the xargs delimiter to a newline:
ls | egrep ‘. ‘ | xargs -d ‘\n’ rm (don’t do this. read on)
But what if the filename contains a newline?
touch «filename with blanks and newline»
Because Unix filenames can contain blanks and newlines, this default behaviour is often problematic; filenames containing blanks and/or newlines are incorrectly processed by xargs. In these situations it is better to use the -0 option, which prevents such problems.
ls is really a tool for direct consumption by a human, instead we need to use the find command which can separate the filenames with a null character ( -print0 ). We also need to tell grep to use null characters to separate the input ( -z ) and output ( -Z ). Finally, we tell xargs to also use null characters ( -0 )
find . -type f -print0 | egrep ‘. ‘ -z -Z | xargs -0 rm
How do I delete files with spaces in them in bash script?
this is a three part topic to a two part process that still is not working for me: Objective: to manipulate a filename then delete it the filename has spaces between the words then the dot .ext Solution: 1) remove all the white space between the words making on long string of chars with no white space between then then delete that file. or 2) place quotes on both sides of the filename with spaces then delete that file. what I did to get my solution. using three different way to reach my solution for the first part of my objective, still not reaching my solution for the second part of my objective. first how I got my filename out of a directory into a variable.
find $PWD -name "*.mp3" | while [ $xf -le $MAXNUM ] ; do read FILENAME;
the variable $FILENAME returned the complete path/filename ‘/home/userx/ffmpegdir/sub/file with — lots of spaces and __ —— _ &&. *# $$ LSD —-in the name _(3).mp3′ I used basename to strip the filename off that string to give me just the filename using just the pref and ext variables. #strip the old file name off the path from FILENAME
c=$FILENAME xpath=$ xbase=$ xfext=$ xpref=$ path=$ pref=$ ext=$
#puts quote marks on both sides of the file #with spaces adding the dot (.) # extention "mp3" giving me a new file name #with the same ext. differentquotes="$.$"
when I call rm to remove the file I add quotes around that file name like this
that calls to the rm like this with the quotes on both end of the file
then all I get is a return error like this
rm: cannot remove `»file with — lots of spaces and __ —— _ &&. *# $$ LSD —-in the name _(3).mp3″‘: No such file or directory
so I decided to try just removing all the spaces between the file name then tried to delete it like this
oldname="$.$" echo "$" "the hole name now is that " echo echo "calling rm" "$\"\"" rm "$"
and I got this result, it removed all the spaces between the file name but I still received an error return from rm.
- oldname=’filewith—lotsofspacesand_——&&. *#$$LSD—-inthename_(3).mp3′
- rm ‘filewith—lotsofspacesand_——&&. *#$$LSD—-inthename_(3).mp3′ rm: cannot remove `filewith—lotsofspacesand_——&&. *#$$LSD—-inthename_(3).mp3′: No such file or directory
so I then tried it like this. I removed all the space within just the pref var first while assigning it to another var name then put the ext on to it then tried to remove it and got this with the same error
anothernewname="$" echo $ putthemtogether="$.$" echo $ rm "$"
I removed all the spaces between the words in just the pref : + anothernewname=’filewith—lotsofspacesand_——&&. *#$$LSD—-inthename_(3)’
then I put the ext back onto the different variable name here:
then I called rm to remove it and still got the same error :
rm: cannot remove `filewith—lotsofspacesand_——&&. *#$$LSD—-inthename_(3).mp3′: No such file or directory + echo
all three times I get the same error- No such file or directory
what is the answer to “what I am doing wrong so that I no longer do it?”
added this: I just tried this: adding the path vatiable to tell it where it is path/filename
rm: cannot remove `/home/userx/ffmpegdir/sub/"file with -- lots of spaces and ____ ----- ___ &&. *# $$ LSD ----in the name _(3).mp3"': No such file or directory
if I put that into the terminal just like that it would work: rm path/»file name with spaces.ext» just as it reads above — is that not a yes, too?