gpt4 book ai didi

bash - 是否有可用的文件和目录名称 "escape converter"?

转载 作者:行者123 更新时间:2023-11-29 08:54:51 26 4
gpt4 key购买 nike

有一天我不得不编写一个 BASH 脚本来遍历任意目录树并查看任意文件并尝试确定有关它们之间比较的内容。我认为这将是一个简单的几个小时 tops! 过程 - 不是这样!

我的挂断电话是有时一些白痴 - 啊哈! - 对不起,可爱的用户 选择在目录和文件名中放置空格。这会导致我的脚本失败。

完美的解决方案,除了威胁那些坚持在这些地方使用空格的人的断头台(更不用说那些把它放在操作系统代码中的人!),可能是一个例行公事它为我们“转义”了文件名和目录名,有点像 cygwin 如何将例程从 unix 文件名格式转换为 dos 文件名格式。在标准的 Unix/Linux 发行版中有这样的东西吗?

请注意,当尝试比较目录树时,简单的for file in * 结构效果不佳,因为它 对“当前目录”有效- 而且,在这种情况下,就像在许多其他情况下一样,不断地 CD 到不同的目录位置会带来自己的问题。所以,在做作业时,我发现了这个问题Handle special characters in bash for...in loop并且建议的解决方案卡在目录名称中的空格上,但可以像这样简单地克服:

dir="dirname with spaces"
ls -1 "$dir" | while read x; do
echo $x
done

请注意: 上面的代码不是特别好,因为 while 循环内使用的变量在 while 循环外是不可访问的。这是因为在通过管道传输 ls 命令的输出时会创建一个隐含的子 shell。 这是促使我查询的关键因素!

...好吧,上面的代码在很多情况下都有帮助,但“转义”字符也会非常强大。例如,上面的目录可能包含:

dir\ with\ spaces

这是否已经存在而我只是忽略了它?

如果没有,有没有人有一个简单的建议来编写一个 - 也许用 sed 或 lex? (我都远不能胜任。)

最佳答案

为测试制作一个非常讨厌的文件名:

mkdir escapetest
cd escapetest && touch "m'i;x&e\"d u(p\nmulti)\nlines'\nand\015ca&rr\015re;t"

[ 编辑: 很可能我打算让 touch 命令成为:

touch $'m\'i;x&e\"d u(p\nmulti)\nlines\'\nand\015ca&rr\015re;t'

这会在文件名中加入更多难看的字符。输出看起来会有点不同。 ]

然后运行:

find -print0 | while read -d '' -r line; do echo -en "--[${line}]--\t\t"; echo "$line"|sed -e ':t;N;s/\n/\\n/;bt' | sed 's/\([ \o47()"&;\\]\)/\\\1/g;s/\o15/\\r/g'; done

输出应该是这样的:

--[./m'i;x&e"d u(pmulti)lines're;t]--         ./m\'i\;x\&e\"d\ u\(p\\nmulti\)\\nlines\'\\nand\\015ca\&rr\\015re\;t

This consists of a condensed version of Pascal Thivent's sed monster, plus handling for carriage returns and newlines and maybe a bit more.

The first pass through sed merges multiple lines into one delimited by "\n" for filenames that have newlines. The second pass replaces any from a list of characters with a backslash preceding itself. The last part replaces carriage returns with "\r".

One thing to note is that, as you know, while will handle spaces and for won't but by sending the output of find with null termination and setting the delimiter of read to null, you can also handle newlines in filenames. The -r option causes read to accept backslashes without interpreting them.

Edit:

Another way to escape the special characters, this time without using sed, uses the quoting and variable-creating feature of the Bash printf builtin (this also illustrates using process substitution rather than a pipe):

while read -d '' -r file; do echo "$file"; printf -v name "%q" "$file"; echo "$name"; done< <(find -print0)

变量 $name 将在循环外可用,因为使用进程替换可防止在循环周围创建子 shell。

关于bash - 是否有可用的文件和目录名称 "escape converter"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1934111/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com