我需要一些关于 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
路径时,操作系统已经为您完成了这一操作。