我正在尝试执行以下命令
ls -d a* | xargs -i sudo rm -rf {}/*
问题是当我添加该/*
部分时该命令不起作用。我想删除目录内容(而不是目录本身)。
答案1
关于什么rm -r a*/*
?这应该可以解决你的问题。
答案2
像这样的命令rm
依赖 shell 来扩展通配符,因此您需要在某个地方调用 shell。
也许
ls -d a* | xargs -i sh -c sudo rm -rf {}/*
答案3
(警告:我还没有测试过这些命令。可能存在拼写错误或错误。首先尝试使用echo
orls
和 no 的所有内容sudo
。)
一般建议:xargs
很少是最简单的做某事的方法。如果没有-i
(顺便说一下,不推荐使用,请使用便携式-I {}
代替),xargs
需要没有标准或通用工具产生的输入格式。使用-I
,xargs
确实有一些用处,但如果您使用管道find
,find -exec
则更简单。
您需要一个 shell 来扩展{}/*
,并且该 shell 必须在{}
被一个实际路径替换后才起作用。一个简单的解决方案是在 shell 中逐行处理。请注意,使用三种模式来捕获目录中的所有文件,因为*
省略了点文件;如果某些模式与任何文件不匹配也没关系,因为rm -f
会忽略任何不引用现有文件的参数。
… |
while read -r line; do
sudo rm -rf -- "$line"/* "$line"/.[!.]* "$line"/..?*
done
Xargs 在这里没有用,因为您必须在某个时刻一个接一个地处理文件,以便让 shell 执行通配符。然而,由于通用技术可能很有用,因此这里有一种从 xargs 将文件名返回到 shell 的方法。 The_
是$0
shell 的参数(它的存在部分是为了不必费心回到$0
任何后续参数,并确保即使$1
以 a 开头一切也能正常工作-
,否则将被视为 shell 的一个选项)。这里有两种方法:要么让 shell 循环遍历其参数,要么告诉 xargs 将单个参数传递给每个 shell 调用。
… | xargs -I {} sudo sh -c 'for x; do rm -rf -- "$x"/* "$x"/.[!.]* "$x"/..?*; done' _ {}
… | xargs -I {} -n 1 sudo sh -c 'rm -rf -- "$1"/* "$1"/.[!.]* "$1"/..?*' _ {}
我假设这ls -d a*
是一个玩具示例,并且您有一个更复杂的命令,每行生成一个文件名。请注意,这ls -d a*
将不是在那里工作,因为大多数ls
实现不会透明地输出不可打印的字符。如果…
是查找命令,请使用-exec
,如
find a* -exec sh -c 'rm -rf -- "$1"/* "$1"/.[!.]* "$1"/..?*' _ {} \; -prune
答案4
另一种选择是使用 shell 循环而不是调用 xargs。
例如
ls -d a* | while read dir; do sudo rm -rf "$dir"/*; done;
主要是为了举例,您还可以通过将 shell 构造放在管道中间来组合这两种技术:
ls -d a* | while read dir; do ls -d "$dir"/*; done | xargs -d \\n rm -rf
xargs 的选项-d
只是指定参数之间的分隔符是换行符,这可以避免包含空格的文件名潜在的灾难性问题(例如deadly / file
)