我正在尝试将 RSA 密钥设置为环境变量,该环境变量作为文本文件包含换行符。
每当我尝试从文件中读取并将其传递到环境变量中时,它都会停在第一行的换行符处。我怎样才能防止这种情况发生?
答案1
请注意,除了 zsh 之外,shell 变量不能存储任意字节序列。所有其他 shell 中的变量不能包含 NUL 字节。对于yash
,它们不能包含不形成有效字符的字节。
对于不包含 NUL 字节的文件,在类似 POSIX 的 shell 中,您可以执行以下操作:
var=$(cat file; echo .); var=${var%.}
我们添加 a.\n
并删除尾随.
以解决$(...)
删除所有尾随换行符的事实。
上面的方法也适用zsh
于包含 NUL 的文件,尽管zsh
您也可以使用$mapfile
特殊的关联数组:
zmodload zsh/mapfile
var=$mapfile[file]
在 zsh 或 bash 中,您还可以使用:
{ IFS= read -rd '' var || :; } < file
最多读取第一个 NUL 字节。除非找到 NUL 字节,否则它将返回非零退出状态。我们在这里使用命令组至少能够告诉打开文件时的错误,但我们无法通过退出状态检测读取错误。
请记住在传递给其他命令时引用该变量。 Newline 是 的默认值$IFS
,因此在 zsh 之外的类 POSIX shell 的列表上下文中不加引号时会导致变量内容被分割(更不用说其他字符$IFS
或通配符的其他问题)。
所以:
printf %s "$var"
例如(不是,当然不是,除了 split+glob 之外,printf %s $var
这还会增加的问题)。echo $var
echo
对于非 POSIX shell:
伯恩外壳:
bourne shell 不支持表单$(...)
也不${var%pattern}
支持运算符,因此很难在那里实现。一种方法是使用eval
和引用:
eval "var='`printf \\' | cat file - | awk -v RS=\\' -v ORS= -v b='\\\\' '
NR > 1 {print RS b RS RS}; {print}; END {print RS}'`"
有了(t)csh
,情况就更糟了,看那里。
使用rc
,您可以使用``(separator){...}
带有空分隔符列表的命令替换形式:
var = ``(){cat file}
答案2
实现此目的的一种方法(包括 的情况0x0
)是将任何二进制数据以编码形式存储在 shell 变量中。
为此,可以使用 Base64 编码(请参阅 RFC 4648)。
例如:
encoded_binary="$( cat binary | base64 -w 0 )"
这-w 0
是相当美观的(它节省了一点点内存)。
当要使用二进制数据时,只能在再次解码后通过管道或重定向来完成。
例如:
{
printf '%s\n' "${passphrase}"
printf '%s' "${encoded_binary}" | base64 -d
} | \
gpg --quiet --batch --passphrase-fd 0 --output - --decrypt
在此示例中,二进制文件是要使用 gpg 解密的 OpenPGP 消息。
base64
可以使用/ uuencode
(uudecode
由 POSIX 指定)来代替。
encoded_binary="$( uuencode -m '/dev/stdout' )"
...
printf '%s' "${encoded_binary}" | uudecode -o '/dev/stdout'
但要注意,这/dev/stdout
应该是一个特殊的符号(而不是一个文件)。 uudecode 的某些实现可以正确支持此功能(例如 GNU),而其他实现则不支持(例如 BusyBox' 仅支持它,因为它已提交c7b90dc4d10ccc4f95940f42676ff907cee73272
并且仅在设置了某些特殊构建选项时才支持)。
另外,如果您有如下结构:
encoded_binary="$(read_function | base64 -w 0)"
您可能仍然想检查退出状态read_function
(或解码时相同),这在 POSIX Shell 命令语言中不能直接实现,但可以间接使用诸如这。
答案3
如果您使用zsh
,您可以像这样分配文件的内容:
p="`cat file_to_be_read`"
答案4
在不支持参数操作方案的传统 bourne shell 上,我们可能会执行以下操作:
NL='
'
var=`cat file`
while case `printf '%s\n' "$var" | wc -l` in "`wc -l < file`" ) break ;; esac
do var=$var$NL; done
其中我们首先从名为 file 的文件的内容开始。现在,如果有任何尾随换行符,则只有循环while
启动。非尾随换行符不会出现任何问题,因为命令替换不会触及它们。
在 while 循环的每次迭代中,换行符都会与变量挂钩,并且由于这不涉及命令 sub(又名 )...
,因此不会发生换行符丢失。