在 bash 脚本中使用字符串参数失败

Using string parameter in bash script failt

提问人:Husker 提问时间:11/9/2023 更新时间:11/10/2023 访问量:88

问:

我需要创建一些证书,并想为此编写一个小的 bash 脚本。

首先,我在创建自己的 bash 脚本方面没有太多经验。

我想将最重要的值(如计算机名称和密码)作为参数传递。不幸的是,我收到错误:

keytool 错误:java.io.IoException:AVA 格式不正确

该错误表示命令中的字符串未正确解释。 我认为问题是我没有正确处理字符串,但我不明白到底出了什么问题。

如果我在终端中输入这样的命令,它可以正常工作

#!/bin/bash

echo "$1" # servername
echo "$2" # domain
echo "$3" # password
echo

keytool -noprompt -keystore $1.$2.truststore.jks -alias CARoot -import -file ca.cert -storetype jks -storepass $3 -keypass $3

keytool -genkey -noprompt -keyalg RSA -storetype pkcs12 -alias $1.$2 -dname $1'.'$2',O=COMPANY,OU=COMPANY,L=NY,ST=NY,C=us' \
      -ext 'SAN=DNS:example1.com,DNS:example2.com'
      -keystore $1.$2'.keystore2.jks' -storepass $3 -keypass $3

你能告诉我我做错了什么吗?

Java Linux Bash Shell 密钥工具

评论

0赞 knittl 11/9/2023
密码值中是否有任何空格或通配符 (, , )?不引用参数扩展将导致这些通配符被计算并扩展到多个路径,并且扩展的值将被空格拆分。*?[...]
0赞 Husker 11/9/2023
是的,我使用两个特殊的字符!和#
0赞 knittl 11/9/2023
!可以在 Bash 中触发历史扩展(这是您正在使用的,即使您的脚本不需要 bash 并且可以正常工作)sh
1赞 user1934428 11/9/2023
要打开跟踪,请将 放入脚本中,或使用 .set -xbash -x SCRIPTNAME ...
2赞 Ed Morton 11/10/2023
您缺少行尾的反斜杠,因此与它上面的行有一个单独的命令。正如您使用的 bash 标签所指示的那样 - “对于有语法或其他错误的 shell 脚本,请在 shellcheck.net 处检查它们,然后再在此处发布它们。shellcheck 还可以告诉您代码中的其他几个问题。如果您在纠正这些问题后仍有问题,请告诉我们。-ext 'SAN=DNS:example1.com,DNS:example2.com'-keystore $1.$2'.keystore2.jks' -storepass $3 -keypass $3

答:

-1赞 Vinith_jk_bro 11/9/2023 #1

这是您处理空格和连接字符串的方式。在脚本中传递参数时,需要正确引用变量以处理值包含空格的情况。

请尝试以下修改后的脚本版本:

#!/bin/bash
server_name="$1"
domain="$2"
password="$3"
echo "$server_name"
echo "$domain"
echo "$password"
keytool -noprompt -keystore "$server_name.$domain.truststore.jks" -alias CARoot -import -file ca.cert -storetype jks -storepass "$password" -keypass "$password"
keytool -genkey -noprompt -keyalg RSA -storetype pkcs12 -alias "$server_name.$domain" -dname "$server_name.$domain,O=COMPANY,OU=COMPANY,L=NY,ST=NY,C=us" \
      -ext "SAN=DNS:example1.com,DNS:example2.com" -keystore "$server_name.$domain.keystore2.jks" -storepass "$password" -keypass "$password"

此脚本正确引用变量,并确保正确处理文件名和带空格的值。快来试试吧!

评论

0赞 Husker 11/9/2023
我明白你的意思。我已经重建了它,但不幸的是错误仍然存在。第一个命令有效。只有使用第二个命令才会发生错误。
0赞 Husker 11/9/2023
在我看来,bash 在执行命令时省略了“ 。
0赞 Vinith_jk_bro 11/9/2023
该问题似乎与您在第二个 keytool 命令中处理可分辨名称 (DN) 的方式有关。可能是 DN 中的空格导致了问题。
0赞 Vinith_jk_bro 11/9/2023
keytool -genkey -noprompt -keyalg RSA -storetype pkcs12 -alias “$server_name.$domain” \ -dname “CN=$server_name.$domain, O=COMPANY, OU=COMPANY, L=NY, ST=NY, C=us” \ -ext “SAN=DNS:example1.com,DNS:example2.com” \ -keystore “$server_name.$domain.keystore2.jks” -storepass “$password” -keypass “$password”
0赞 knittl 11/9/2023
@Husker不是值的一部分,而是 shell 语法的一部分。如果要求引号成为值的一部分,则必须写成 或 。""\"...\""'"..."'
0赞 Ed Morton 11/10/2023 #2

试试这个,使用正确的引号,正确的换行符,并将缺少的添加到选项字符串中。CN=-dname

keytool -genkey -noprompt -keyalg RSA -storetype pkcs12 -alias "$1.$2" \
      -dname "CN=$1.$2,O=COMPANY,OU=COMPANY,L=NY,ST=NY,C=us" \
      -ext 'SAN=DNS:example1.com,DNS:example2.com' \
      -keystore "$1.$2.keystore2.jks" -storepass "$3" -keypass "$3"

调查详情和观察结果如下...

您在评论中告诉我们这有效:

server_name="$1"
domain="$2"
password="$3"

keytool -noprompt -keystore "$server_name.$domain.truststore.jks" -alias CARoot -import -file ca.cert -storetype jks -storepass "$password" -keypass "$password"

您在另一条评论中告诉我们这有效:

keytool -genkey -noprompt \
-keyalg RSA \
-storetype pkcs12 \
-alias server.example.com \
-dname 'CN=server.example.com,O=COMPANY,OU=COMPANY,L=NY,ST=NY,C=US' \
-ext "SAN=DNS:example.com, DNS:example2.com" \
-keystore server.example.com.keystore.jks \
-storepass 'passwort!#' \
-keypass 'passwort!#'

如果上面的第二个带有硬编码值的脚本有效,那么这个使用变量的脚本也必须有效,我们稍后将从脚本参数填充选项:

#!/usr/bin/env bash

the_alias='server.example.com'
the_dname='CN=server.example.com,O=COMPANY,OU=COMPANY,L=NY,ST=NY,C=US'
the_keystore='server.example.com.keystore.jks'
the_pass='passwort!#'

keytool -genkey -noprompt \
-keyalg RSA \
-storetype pkcs12 \
-alias "$the_alias" \
-dname "$the_dname" \
-ext 'SAN=DNS:example.com, DNS:example2.com' \
-keystore "$the_keystore" \
-storepass "$the_pass" \
-keypass "$the_pass"

如果这可行,那么我们只需要映射在不起作用的命令中用作选项的值(从您的问题中复制并每行布置一个,以便与我正在使用的其他脚本进行比较,并修复了缺失的转义):

keytool -genkey -noprompt \
-keyalg RSA \
-storetype pkcs12 \
-alias $1.$2 \
-dname $1'.'$2',O=COMPANY,OU=COMPANY,L=NY,ST=NY,C=us' \
-ext 'SAN=DNS:example1.com,DNS:example2.com' \
-keystore $1.$2'.keystore2.jks' \
-storepass $3 \
-keypass $3

要填充我们从传递给脚本的参数中引入的变量,而不是对它们进行硬编码,这必须有效:

#!/usr/bin/env bash

the_alias="$1.$2"
the_dname="CN=${the_alias},O=COMPANY,OU=COMPANY,L=NY,ST=NY,C=us"
the_keystore="${the_alias}.keystore.jks"
the_pass="$3"

keytool -genkey -noprompt \
-keyalg RSA \
-storetype pkcs12 \
-alias "$the_alias" \
-dname "$the_dname" \
-ext 'SAN=DNS:example.com, DNS:example2.com' \
-keystore "$the_keystore" \
-storepass "$the_pass" \
-keypass "$the_pass"

其中,您将上述内容称为:

./the_script 'server' 'example.com' 'passwort!#'

那么 - 这行不通?如果没有,我提供的上述 2 个脚本中哪一个失败了?

在进行编码时,我注意到,除了失败脚本中缺少引号和行尾缺少的反斜杠之外:-ext

  • 你说有效的代码版本使用,而你说的版本不起作用使用(注意keystore.jkskeystore2.jks2)
  • 同样,对于 vs(注意 的 )。SAN=DNS:example.comSAN=DNS:example1.com1
  • 后面的空白字符仅存在于工作选项字符串中。,-ext
  • 工作脚本中的选项将启动 而在失败的那个中,它没有。-dnameCN=

这些都有问题吗?

评论

1赞 Husker 11/10/2023
太好了,现在它起作用了,我一定在不断编辑过程中丢失了 DN。非常感谢您的详细回复。