使用 bash 处理由路径名组成的文本文件

使用 bash 处理由路径名组成的文本文件

我需要一些关于 bash 处理文本文件的帮助。为了清理数十年来的 Windows 使用,我编写了一个简单的命令来查找特定文件的所有实例 - 特别是所有 Desktop.ini 文件。据我所知,这个结果是完美的。

find . -name "desktop.ini" > ~/desktop-ini.txt 给出 1038 行:

./Billy Joel/Greatest Hits,第 1 卷和第 2 卷 (1973-1985),光盘 1/desktop.ini
./Billy Joel/Greatest Hits,第 1 卷和第 2 卷 (1973-1985),光盘 2/desktop.ini
./Billy Joel/desktop.ini

所以现在,我想使用 shell 脚本删除所有这些文件,但正如您所看到的,有大量不可预测的“特殊字符”会使简单的 rm <$filepath> 脚本出问题。我试过(一次)用单引号 (') 将整个字符串括起来 - 成功了。

rm'./Aerosmith/Classics Live!, Vol. 2/desktop.ini'

但在 shell 脚本中(用 ls 语法替换 rm 语法),它崩溃了(当然)。有人能给我指出“操作方法”或资源(除了一般的正则表达式、sed 或 awk 文本)来了解如何处理文件路径以使其正确显示吗?

我想到了一些方法,比如计算“/”字符的数量、找到最后一个字符、创建一个新字符串、“cd”到该目录、删除文件、返回根目录并重复。这在逻辑上是合理的,但它要求字符串不破坏代码 - 到目前为止确实如此。感谢您对此的任何想法。

答案1

$ find . -name "desktop.ini" | sed -re "s/^/rm '/" -e "s/$/'/"

...创建要执行的命令,因此 - 在检查输出的正确性之后......

... | bash
最后就应该让它发生。


$ sed -re <~/desktop-ini.txt "s/^/rm'/" -e "s/$/'/"
rm'./Billy Joel/Greatest Hits,第 1 卷和第 2 卷(1973-1985),第 1 盘/desktop.ini'
rm'./Billy Joel/Greatest Hits,第 1 卷和第 2 卷(1973-1985),第 2 盘/desktop.ini'
rm'./Billy Joel/desktop.ini'

答案2

从你的例子来看,你似乎试图让“找到”生成脚本它将在稍后运行某些东西,而不是直接运行某些东西,尽管我怀疑你真的只想直接运行某些东西。

如果您将文件名读入 shell 变量,则可以使用${...@Q}较新的 Bash 版本要求它以稍后可以取消引用的方式引用值。它将处理可能导致问题的任何特殊字符

find (or cat) ... | while IFS="" read -r path; do
    echo "rm ${path@Q}"
done

对于旧版本:

...; do
    printf 'rm %q\n' "$path"
done

但所有这些都是仅有的如果您特别想要一个两步过程(即首先生成一个 shell 脚本,然后运行该 shell 脚本),则需要这样做。如果您想要的只是立即为每一行运行某些操作 – 您根本不需要处理特殊字符,只要变量扩展本身放在引号内即可。

find or cat | while IFS="" read -r path; do
    rm -i "$path"
done

(这是因为变量扩展是不是“宏”扩展 – 解释器将“变量周围的引号”识别为与“扩展值一部分的引号”不同的东西。因此,即使 $path 包含 a"或其$本身,也不会影响结果。)

更传统的方法是运行该命令。其默认模式也需要带引号的输入,但对于您来说,只需指定分隔符xargs即可:\n

find (or cat) ... | xargs -d '\n' rm -i

最后,GNU find 还可以自行运行命令:

find ... -exec rm -i {} \;
find ... -ok rm {} \;

我想到了一些事情,比如计算“/”字符的数量,找到最后一个字符,创建一个新字符串,然后“cd”到该目录,

rm这没用;当您尝试或ls路径时,操作系统已经为您完成了这一操作。

相关内容