【问题标题】:Bash variable is causing disorder to the expected output [duplicate]Bash变量导致预期输出混乱[重复]
【发布时间】:2021-10-20 10:29:30
【问题描述】:

我正在尝试创建 JSON 数据并将其存储到文件中,然后将其提供给我将要进行的 API 调用。但是,在格式化我的 echo 命令的输出以制作 JSON 格式时,一个变量会导致返回的输出混乱。下面是我的脚本

  cat "${SETTINGS_LIST}" | while read endpoint
  do
    echo "{\"id\": \"$n\", \"method\": GET, \"url\": \"$endpoint\"}"
    let n=n+1
  done

那么这是 SETTING_LIST 变量的内容

/accounting-rules
/aging-buckets
/application-rules
/audit-trail-settings
/batch-aliases
/billing-cycle-types
/billing-list-price-bases
/billing-period-starts
/billing-periods
/billing-rules

输出是这样返回的:

"}id":"0","method":"GET","url":"/accounting-rules
"}id":"1","method":"GET","url":"/aging-buckets
"}id":"2","method":"GET","url":"/application-rules
"}id":"3","method":"GET","url":"/audit-trail-settings
"}id":"4","method":"GET","url":"/batch-aliases
"}id":"5","method":"GET","url":"/billing-cycle-types
"}id":"6","method":"GET","url":"/billing-list-price-bases
"}id":"7","method":"GET","url":"/billing-period-starts
"}id":"8","method":"GET","url":"/billing-periods
"}id":"9","method":"GET","url":"/billing-rules

当我删除 endpoint 变量并将其更改为此时,例如

echo "{\"id\": \"$n\", \"method\": GET, \"url\": \"/application-rules\"}"

我得到了预期的输出

{"id": "0", "method": GET, "url": "/application-rules"}
{"id": "1", "method": GET, "url": "/application-rules"}
{"id": "2", "method": GET, "url": "/application-rules"}
{"id": "3", "method": GET, "url": "/application-rules"}
{"id": "4", "method": GET, "url": "/application-rules"}
{"id": "5", "method": GET, "url": "/application-rules"}
{"id": "6", "method": GET, "url": "/application-rules"}
{"id": "7", "method": GET, "url": "/application-rules"}
{"id": "8", "method": GET, "url": "/application-rules"}
{"id": "9", "method": GET, "url": "/application-rules"}

我做过的事情:

  1. 降级到较旧的 git bash 版本
  2. 在我的 Ubuntu WSL 中尝试过,但仍然遇到同样的错误。
  3. 尝试使用 JQ 和 printf 命令将输出格式化为 JSON 的不同方式,但问题仍然存在
  4. 脚本在具有相同 BASH 和 GIT BASH 版本的不同机器上运行良好

有人知道这个问题的原因以及如何解决这个问题吗?

【问题讨论】:

    标签: bash variables echo


    【解决方案1】:

    欢迎来到关于 Unix 和 Windows 对行尾的不同看法的历史小课!

    在 Unix(和 Linux、Ubuntu 等)上,行尾定义为单个 \n 字符。

    在 Windows 上,它是两个字符的序列 \r\n

    (为了完整起见,在旧 Mac 上它是一个 \r,但今天这几乎无关紧要。)

    您有一个可爱的、与 Windows 兼容的文本文件,其中的行由 \r\n 分隔。然而,作为 Unix 工具,Bash 不会专门处理 \r,并且仅在 \n 字符处拆分行。

    因此,$endpoint 变量的每个实例最后都包含一个 \r

    现在,\r 也被称为“回车”,来自旧打字机,这正是 Bash 的输出例程所做的,当它遇到 \r 时:跳回当前行的开头并替换所有字符接下来是什么。这就是为什么您会看到如此奇怪的乱码输出。

    修复:在使用变量之前删除 \r。例如,this question 的答案提出了这样的解决方案:

    cat "${SETTINGS_LIST}" | while IFS= read -r endpoint
    do
        endpoint="${endpoint%$'\r'}"
        echo "{\"id\": \"$n\", \"method\": GET, \"url\": \"$endpoint\"}"
        let n=n+1
    done
    

    【讨论】:

    • 你是一个伪装成人类的神。我非常感谢您的帮助以及您提供的其他信息。这对我来说完全有意义。
    • 顺便说一句,while 命令后 IFS 的作用是什么?
    • IFS 是一个 bash 内部变量,即“内部字段分隔符”字符 tldp.org/LDP/abs/html/internalvariables.html#IFSREF 。 Bash 将使用此变量中的字符来拆分条目。将其设置为空值意味着“不要做任何意外的事情,只在\n 处拆分”。 unix.stackexchange.com/questions/26784/understanding-ifs 有很好的例子。
    【解决方案2】:

    您的设置列表中显然有回车字符。将cat "${SETTINGS_LIST}" 替换为dos2unix < "${SETTINGS_LIST}",即

    dos2unix <"${SETTINGS_LIST}"` | while read endpoint
    

    如果你还没有dos2unix(我不记得它是否随 Mac 一起提供),install it from the Appstore

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-02
      相关资源
      最近更新 更多