Xargs 和 rm 带 *

Xargs 和 rm 带 *

我正在尝试执行以下命令

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

警告:我还没有测试过这些命令。可能存在拼写错误或错误。首先尝试使用echoorls和 no 的所有内容sudo。)

一般建议:xargs很少是最简单的做某事的方法。如果没有-i(顺便说一下,不推荐使用,请使用便携式-I {}代替),xargs需要没有标准或通用工具产生的输入格式。使用-I,xargs确实有一些用处,但如果您使用管道findfind -exec则更简单。

您需要一个 shell 来扩展{}/*,并且该 shell 必须在{}被一个实际路径替换后才起作用。一个简单的解决方案是在 shell 中逐行处理。请注意,使用三种模式来捕获目录中的所有文件,因为*省略了点文件;如果某些模式与任何文件不匹配也没关系,因为rm -f会忽略任何不引用现有文件的参数。

… |
while read -r line; do
  sudo rm -rf -- "$line"/* "$line"/.[!.]* "$line"/..?*
done

Xargs 在这里没有用,因为您必须在某个时刻一个接一个地处理文件,以便让 shell 执行通配符。然而,由于通用技术可能很有用,因此这里有一种从 xargs 将文件名返回到 shell 的方法。 The_$0shell 的参数(它的存在部分是为了不必费心回到$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

相关内容