Bash Mapfile 变量添加 Space

Bash Mapfile Var Adds Space

我很困惑为什么会这样。

我想将交互式提示中的多行 var 粘贴到 mapfile 中,然后像使用文件对象一样使用所述 mapfile。

出于某种原因我可以忍受回声中断并使用 printf 但为什么在将 mapfile var 分配给另一个(全局)var 时添加前导 space?

#!/bin/bash

global_privkey=""

myfunc(){
  local input_pattern

  # Paste SSH privkey.
  builtin echo "paste your privkey:"
  builtin mapfile input_pattern

  # Adds leading space!
  builtin echo "echo (adds space):"
  builtin echo "${input_pattern[@]}"

  # Works.
  builtin echo "printf (good):"
  builtin printf "%s" "${input_pattern[@]}"
  builtin echo

  # Adds leading space!
  global_privkey="${input_pattern[@]}"
}

myfunc

# Leading space!
builtin echo "global printf (adds space from var assignment):"
builtin printf "%s" "$global_privkey"
builtin echo

exit 0

输出:

arch :: ~/scripts % ./input_privkey_minimal.sh
paste your privkey:
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCzzWDcxsfWJ0NI15wBtPLqQPfryYDSZz8jN+eSk7+pdAAAALD7CKEF+wih
BQAAAAtzc2gtZWQyNTUxOQAAACCzzWDcxsfWJ0NI15wBtPLqQPfryYDSZz8jN+eSk7+pdA
AAAED6QmKlvu9ASHyHHBm7oLq7l2AMglXKq+uJ9IlbZBDbc7PNYNzGx9YnQ0jXnAG08upA
9+vJgNJnPyM355KTv6l0AAAAKHJvYmVydEAxMDItMTgyLTE1NS0zNS5pcC5hZnJpaG9zdC
5qb2J1cmcBAgMEBQ==
-----END OPENSSH PRIVATE KEY-----
echo (adds space):
-----BEGIN OPENSSH PRIVATE KEY-----
 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
 QyNTUxOQAAACCzzWDcxsfWJ0NI15wBtPLqQPfryYDSZz8jN+eSk7+pdAAAALD7CKEF+wih
 BQAAAAtzc2gtZWQyNTUxOQAAACCzzWDcxsfWJ0NI15wBtPLqQPfryYDSZz8jN+eSk7+pdA
 AAAED6QmKlvu9ASHyHHBm7oLq7l2AMglXKq+uJ9IlbZBDbc7PNYNzGx9YnQ0jXnAG08upA
 9+vJgNJnPyM355KTv6l0AAAAKHJvYmVydEAxMDItMTgyLTE1NS0zNS5pcC5hZnJpaG9zdC
 5qb2J1cmcBAgMEBQ==
 -----END OPENSSH PRIVATE KEY-----

printf (good):
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACCzzWDcxsfWJ0NI15wBtPLqQPfryYDSZz8jN+eSk7+pdAAAALD7CKEF+wih
BQAAAAtzc2gtZWQyNTUxOQAAACCzzWDcxsfWJ0NI15wBtPLqQPfryYDSZz8jN+eSk7+pdA
AAAED6QmKlvu9ASHyHHBm7oLq7l2AMglXKq+uJ9IlbZBDbc7PNYNzGx9YnQ0jXnAG08upA
9+vJgNJnPyM355KTv6l0AAAAKHJvYmVydEAxMDItMTgyLTE1NS0zNS5pcC5hZnJpaG9zdC
5qb2J1cmcBAgMEBQ==
-----END OPENSSH PRIVATE KEY-----

global printf (adds space from var assignment):
-----BEGIN OPENSSH PRIVATE KEY-----
 b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
 QyNTUxOQAAACCzzWDcxsfWJ0NI15wBtPLqQPfryYDSZz8jN+eSk7+pdAAAALD7CKEF+wih
 BQAAAAtzc2gtZWQyNTUxOQAAACCzzWDcxsfWJ0NI15wBtPLqQPfryYDSZz8jN+eSk7+pdA
 AAAED6QmKlvu9ASHyHHBm7oLq7l2AMglXKq+uJ9IlbZBDbc7PNYNzGx9YnQ0jXnAG08upA
 9+vJgNJnPyM355KTv6l0AAAAKHJvYmVydEAxMDItMTgyLTE1NS0zNS5pcC5hZnJpaG9zdC
 5qb2J1cmcBAgMEBQ==
 -----END OPENSSH PRIVATE KEY-----

对脚本的一些修复:

#!/usr/bin/env bash

global_privkey=""

myfunc(){
  local input_pattern

  # Paste SSH privkey.
  echo "paste your privkey:"
  mapfile -t input_pattern

  # Adds leading space!
  echo "echo (adds space):"
  echo "${input_pattern[@]}"

  # Works.
  echo "printf (good):"
  printf %s\n "${input_pattern[@]}"
  echo

  # Delete BEGIN END entries
  unset 'input_pattern[0]' 'input_pattern[-1]'

  # Join lines into a single string
  printf -v global_privkey %s "${input_pattern[@]}"

}

myfunc

# Leading space!
echo "global printf (adds space from var assignment):"
printf %s\n "$global_privkey"

why this happens.

Adds leading space!

当然可以 - echo 用 space 分隔参数。

$ echo '1'       "2"           3
1 2 3             # wow single spaces

$ a=(1     2    '3     var     with  spaces')
$ echo "${a[@]}"
1 2 3     var     with  spaces       # arguments contents are preserved

当您将多个参数传递给 echo 时,这些参数由 space 分隔。

mapfile 不会从数组元素中删除尾随分隔符。所以每个数组元素都以换行符结尾。另外 echo 输出第二个换行符,所以打印出两个换行符,导致一个空行。

$ a=(1$'\n' 2$'\n' 3$'\n')    # mapfile leaves newline in variables
$ set -x
$ echo "${a[@]}"
+ echo '1
' '2
' '3
'      # executes echo with 3 arguments, each with a newline
1
 2     # echo outputs values separated by spaces
 3
       # echo outputs extra newline

# the echo "${a[@]}" is equal to:
$ echo 1$'\n' 2$'\n' 3$'\n'
1
 2
 3

$

并且当数组在分配中使用 ${array[@]} 扩展时,数组元素使用 IFS 中的第一个字符连接,默认情况下为 space。在该上下文中它等于 ${array[*]}(因为“单词”在赋值时连接在一起)。

$ set -x
$ a=(1 2 3)
+ a=(1 2 3)
$ echo "${a[@]}"
+ echo 1 2 3  # passes 3 arguments
1 2 3
$ echo "${a[*]}"
+ echo '1 2 3'  # passes 1 argument separated by first character in IFS
1 2 3
$ ( IFS='|'; printf "%s\n" "${a[*]}"; ) # well known method for printing arrays
+ IFS='|'
+ printf '%s\n' '1|2|3'
1|2|3
$ b="${a[@]}"
+ b='1 2 3'   # wow, spaces
$ b="${a[*]}"
+ b='1 2 3'   # * will be equal to @ in assignment

使用 [*][@] 的数组扩展的处理方式类似于 $*$@ 处理位置参数。对于更广泛的示例,我推荐 Posix Rationale for Shell and Utilities C.2.5 Parameters and Variables,它与 $* $@ 一起使用,但它与数组相同。