Bash打印转义文件内容

6
我试图打印带有转义双引号的文件内容。
# read file contents from ${filename}
# - escape double quotes
# - represent newlines as '\n' 
# print the result
echo "my file contents: \"${out}\""

那么举个例子,如果我的文件是

<empty line>
console.log("hello, world");
<empty line>

应该打印

my file contents: "\nconsole.log(\"hello, world\");\n"

我试图使用printf以%q格式说明符输出内容,但遇到了它会删除尾随空格的问题。

哇,这是相当不寻常的壮举。为什么?[如果您愿意,我可以为此编写一个C程序] - Paul Stelian
展示一下你是如何尝试使用printf %q的--我向你保证,它本身并不会删除尾随空格。然而,如果你在命令替换中运行它(或以这种方式运行cat),情况就不同了... - Charles Duffy
1
@PaulStelian 我也可以用C语言写;) 我想要一个简短的脚本来完成这个任务。 - Petr Petrov
1
@PetrPetrov,没错,因为 $(cat file) 本身会删除尾随的换行符。相反,请尝试:IFS= read -r -d '' content <file; printf '%q\n' "$content" - Charles Duffy
@CharlesDuffy 它给了我 $'\nconsole.log("hello, world");\n\n'。去掉前导的 $' 和尾随的 ' 是正常做法吗?双引号需要转义吗?我需要使用 tr 或 sed 吗?我以为 "%q" 可以解决这个问题。 - Petr Petrov
显示剩余4条评论
3个回答

7

要仅执行您明确请求的两个文字转换:

IFS= read -r -d '' content <file
content=${content//'"'/'\"'/}
content=${content//$'\n'/'\n'}
echo "file contents: $content"

话虽如此,如果你想将任意内容表示为JSON字符串,让一个完全符合标准的JSON解析器/生成器来处理吧:

IFS= read -r -d '' content <file
echo "file contents: $(jq -n --arg content "$content" '$content')"

...或者更好的方法(以支持即使bash无法存储为字符串的内容),让jq直接从输入文件中读取:

echo "file contents: $(jq -Rs . <file)"

3

命令替换会去掉尾随的换行符。您可以通过添加一个虚拟的非换行符字符,然后再删除它来防止这种情况:

printf '\n\nfoo\n\n' > file

contents="$(cat "file"; printf x)"
contents="${contents%x}"

printf "The shell equivalent of the file contents is: %q\n" "$contents"

如果您想生成JSON,应该使用jq


3
我也经常使用IFS= read -r -d '' contents <file这条命令,假设文件中没有NUL字符——即使有NUL字符,也无法将其存储在Shell变量中——这个命令可以正常工作,但是它有一个缺点,就是在执行read命令时,会返回非零的退出状态。 - Charles Duffy

2

在我看来,将任意多行文本转换为printf格式的最可靠方法似乎是使用bash内置的printf。

$ nl -ba testfile
     1
     2  console.log("hello, world");
     3
$ s="$(printf '%q' "$(cat testfile; printf x)")"
$ s="${s%x\'}"; s="${s#\$\'}"
$ echo "$s"
\nconsole.log("hello, world");\n\n

这样做的好处是处理所有字符,包括CR和tab,而不仅仅是换行符。

请注意我们采用的有趣命令扩展解决方法,以避免剥离尾随的换行符。(否则,我们可以只使用s="$(printf '%q' "$(。)

还要注意在echo之前对行进行的参数扩展。这是必需的,因为bash处理%q格式字符的方式,返回一个格式化引用的字符串,而不仅仅是格式化的字符串。


考虑到 console.log() 是 JavaScript 源代码,很可能 OP 所需的输出实际上是一个 JavaScript 字符串。printf %q 可能在今天适用(我并不断言这是正确的,需要分析),但不能保证它将来也适用 -- 如果 bash 明天引入了新的扩展引用形式,printf %q 将符合规范 使用 这种扩展引用形式。 - Charles Duffy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接