IP 作为 Linux 数组元素抛出 UnknownHostException 但作为常量有效

IP as Linux array element throws UnknownHostException but as constant works

我在目录 /home/test/javacall 中有以下脚本,它解析 IP 对的 csv,调用一个 sh 文件,该文件调用可执行 jar 以从这些 IP 获取输出。

在下面的代码中,ip1=${IPArray[0]} 从 java 中抛出 UnknownHostException。 但是如果我直接使用 ip ip1="10.10.10.10" java 代码工作正常。我从 java 做了 System.out.println 并且在两种情况下都显示了相同的 IP。但仅在 ip1=${IPArray[0]} 的情况下,我得到了例外。

#!/bin/bash

INPUT="IPPairs.csv"
array=()

while IFS="," read var1 var2 ; do
    echo $var1 $var2
    pairString="$var1***$var2"
    array+=("$pairString")
done < $INPUT

for i in "${array[@]}" ; do
    echo $i
    IPString=$(echo $i | tr '***' ' ')
    read -ra IPArray <<< "$IPString"
    ip1=${IPArray[0]}
    #ip1="10.10.10.10"
    ip2=${IPArray[1]}

    source /home/test/javacall/javacmd.sh "$ip1" "/home/test/javacall/out.txt" "show running-config all-properties"
done

异常:

com.jcraft.jsch.JSchException: java.net.UnknownHostException: 10.10.10.10
        at com.jcraft.jsch.Util.createSocket(Util.java:349)
        at com.jcraft.jsch.Session.connect(Session.java:215)
        at com.jcraft.jsch.Session.connect(Session.java:183)

System.out.println() 仅显示 可见 个字符。

如果您的输入文件包含 DOS 换行符,System.out.println() 将不会显示它们,但它们仍会出现在您的命令行中,并被解析为要连接的 IP 地址的一部分,从而导致未知主机异常。将其转换为 UNIX 文本文件,如 dos2unix,或在 vim 中使用 :set fileformat=unix,通常是解决此问题的最快方法。

顺便说一句,如果您不需要保留顺序,关联数组通常是更适合用于存储对的数据结构:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: Bash 4.0+ needed" >&2; exit 1;; esac

declare -A pairs=( )

while IFS=$',\r' read -r var1 var2 _ ; do
    pairs[$var1]=$var2
done <"$input"

for ip1 in "${!pairs[@]}"; do
  ip2=${pairs[$ip1]}
  # Using printf %q causes nonprintable characters to be visibly shown
  printf 'Processing pair: %q and %q\n' "$ip1" "$ip2" >&2
done

在上面,使用 IFS=$',\r' 防止 LF 字符(来自构成 DOS 换行符的 "CRLF" 序列)成为 var1var2 的一部分. (添加一个 _ 占位符变量以使用文件给定行中的任何其他内容为这一点增加了额外的保险)。

该字符串 (35737) 表示您的 csv 文件在文件前面使用 Byte-Order Mark (BOM) 编码。 read 命令不会将 BOM 解释为具有特殊含义,只是传递原始字符,因此您将它们视为输出的一部分。

由于您没有指明源文件是如何生成的,因此您可以调整那一端的设置以防止写入 BOM,这在许多情况下是可选的。或者,您可以在脚本端以各种方式解决它。这些问题都提供了一些例子:

How can I remove the BOM from a UTF-8 file?
Cygwin command not found bad characters found in .bashrc 35737

但老实说,如果您只是遵循 Charles Duffy 的建议并 运行 在解析文件之前通过 dos2unix,它应该会自动为您清理它。即:

...
array=()

dos2unix $INPUT

while IFS="," read var1 var2 ; do
...

或者,以 Charles 的版本为基础:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[123].*) echo "ERROR: Bash 4.0+ needed" >&2; exit 1;; esac

INPUT="IPPairs.csv"
declare -A pairs=( )

dos2unix $INPUT

while IFS=$',\r' read -r var1 var2 _ ; do
    pairs[$var1]=$var2
done <"$INPUT"

for ip1 in "${!pairs[@]}"; do
  ip2=${pairs[$ip1]}
  # Using printf %q causes nonprintable characters to be visibly shown
  printf 'Processing pair: %q and %q\n' "$ip1" "$ip2" >&2
done

请注意,运行在脚本中使用 dos2unix 不一定是最好的方法,因为文件只需要转换一次。一般来说,它应该不会造成任何伤害,尤其是对于这么小的文件。尽管如此,更好的方法是将 运行 dos2unix 作为将您的 csv 推送到服务器的任何进程的一部分,并将其保留在此脚本之外。