for 在名称中包含 \n 字符的文件夹中循环

Tar*_*lpe 9 command-line bash scripts

我有一些带有\n字符名称的文件夹。

例如:

$ ls
''$'\n''Test'
Run Code Online (Sandbox Code Playgroud)

那是指一个带有测试名称的文件夹,名称前有一个空行。

因此,当我在其父目录中运行一些这样的脚本时:

while IFS= read -r d; do 
    rmdir $d
done < <(find * -type d)
Run Code Online (Sandbox Code Playgroud)

表明:

rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory
Run Code Online (Sandbox Code Playgroud)

因为它运行了两次,一次 on\n和另一个 on Test,因为文件夹名称有两行。

那么我该如何解决这个问题,让脚本知道\nTest只有一个文件夹?

Ser*_*nyy 12

您在那里只有一个命令,因此find使用-exec标志调用进行调用就足够了rmdir

find -depth -type d -exec rmdir {} \;
Run Code Online (Sandbox Code Playgroud)

或者使用 中的-delete选项 find -type d -delete,但它不适用于非空目录。为此,您还需要-empty标志。还要注意,-delete意味着-depth可以跳过。因此,另一种可行的替代方法是将所有内容都作为一个过程:

find -type d -empty -delete
Run Code Online (Sandbox Code Playgroud)

如果目录不为空,请使用rm -rf {} \;. 要仅隔离具有\nin 文件名的目录,我们可以将 bash 的ANSI-C 引用 $'...'-name选项结合起来:

find  -type d -name $'*\n*' -empty -delete
Run Code Online (Sandbox Code Playgroud)

POSIX-ly,我们可以这样处理:

find -depth  -type d -name "$(printf '*\n*' )" -exec rmdir {} \;
Run Code Online (Sandbox Code Playgroud)

值得一提的是,如果您的目标是删除目录,那么-delete就足够了,但是如果您想在目录上执行命令,则-exec最合适。

也可以看看

  • *总是*在没有任何破坏性负载的情况下干运行这样的`find`命令(即删除`-delete`或`-exec任何\;`)以检查受影响的文件列表是否确实正确并且不包含应该包含的内容不会被删... (6认同)
  • @dessert 确实如此,我在其中添加了它,但是 `-delete` 不会删除非空目录。因此,*小心*使用`rm -rf` (3认同)
  • ... 使用 `rm -rf` *小心*。;P 顺便说一句,`find` 没有`-delete` 选项吗?它删除空目录并为非空目录抛出错误,例如`rmdir`——可能更便宜。 (2认同)
  • 这是 askubuntu.com,所以我们可以假设 GNU `find`。使用 `-exec rmdir {} +` 将多个 args 批处理到一个 `rmdir` 命令行。顺便说一句“*但它不适用于非空目录。*”也适用于`rmdir`,所以这实际上与`-delete`没有区别。它与 `rm -r` 不同。 (2认同)
  • `find -type d -empty -delete`(`-delete` 意味着 `-depth`)。 (2认同)

Byt*_*der 10

您可以使用 shell globs 而不是find

for d in */ ; do 
    rmdir "$d"
done
Run Code Online (Sandbox Code Playgroud)

shell glob*/匹配当前目录中的所有文件夹。这个 for 循环结构会自动处理正确的分词。

请注意,根据您的 shell 选项,这可能会忽略隐藏文件夹(名称以 . 开头)。可以使用命令更改该行为以匹配当前会话的所有文件shopt -s dotglob

也不要忘记总是引用你的变量。


des*_*ert 6

到目前为止编写的两个答案rmdir每个目录调用一次,但是rmdir我想知道可以使用多个参数:没有更有效的方法吗?

一个可以简单地做

rmdir */
Run Code Online (Sandbox Code Playgroud)

这绝对是最简单和最有效的方法,但在许多目录的情况下可能会引发错误(请参阅gnome-terminal 中命令行参数的最大长度是多少?)。如果您希望这种方法以递归方式工作,请启用globstarshell 选项shopt -s globstar并使用**/*/代替*/

使用 GNU find(如果我们不只是想使用-delete),我们可以做

find -depth -type d -exec rmdir {} +
Run Code Online (Sandbox Code Playgroud)

它构建命令行的方式“与xargs构建其命令行的方式大致相同”(man find)。替代-depth-maxdepth 1,如果你不希望它递归工作。

steeldriver 在这个答案中解释了第三种和 IMO 的绝妙方法:

printf '%s\0' */ | xargs -0 rmdir
Run Code Online (Sandbox Code Playgroud)

这使用内置的 shellprintf来构建一个以零分隔的参数列表,然后将该列表通过管道传输到xargs该列表,rmdir根据需要的频率进行调用。你可以让它递归地工作,shopt -s globstar**/*/不是*/像上面那样。

  • `find` 是递归的,但 OP 的循环不是。要复制该行为,请使用 `find -maxdepth 1 -type d -exec rmdir {} +`。(在这种情况下,`-depth` 是多余的。)用 `printf` 模拟 `find -print0` 的巧妙技巧,我以前从未见过。 (2认同)