Reputation: 12567
If I execute
find . -name \*\.txt | while read f; do /bin/rm -i "$f"; done
rm
asks:
/bin/rm: remove regular empty file ‘./some file name with spaces.txt’?
but the command exits without waiting for the answer. Why is that and how to fix it?
The other question on this subject, https://unix.stackexchange.com/questions/398872/rm-ir-does-not-work-inside-a-loop loops through the ls
output, but in my case STDIN
is the output of find
, with multiple files, each potentially with spaces in them, so I can't switch to non-loop approach.
Upvotes: 0
Views: 414
Reputation: 24802
Instead of looping over the content produced by the default -print
action of find
, use find
's -exec
action :
find . -name \*\.txt -exec rm -i -- {} +
In this command, {}
represents the elements iterated over by find
, and the +
both delimits the command executed by find -exec
and states that it should replace {}
by as many elements it can at once (as an alternative you can use \;
for the command to be executed once per element). --
after rm -i
makes sure the file listed by find
won't be interpreted as rm
options if they start by a dash but correctly as filenames.
Not only is this more concise (although not more easily understandable) , but it also avoids problems related to special characters naïve solutions would have.
Upvotes: 2
Reputation: 295530
while IFS= read -r -d '' f <&3; do
rm -i -- "$f"
done 3< <(find . -name '*.txt' -print0)
read -i
uses for input. Here, we're using FD 3 (3<
on the redirection, and <&3
on the read
alone).-r
to read
, or literal backslashes in your filenames will be consumed by read
rather than placed in the populated variable.-print0
on the find
side, and -d ''
on the read
side.Upvotes: 4
Reputation: 37267
Because rm
inherits its standard input from the loop, which is connected to the output from the left side. So after read f
got the name foo
, there's nothing for rm
to read from stdin. That's why rm
exits on its own.
Don't use pipe if you need rm -i
the prompt. There are many alternatives. One of them is
rm -i $(echo foo)
Upvotes: -1