/usr/local/pgsql15_1/bin/psql test15 <<EOF
begin;
drop COLLATION IF EXISTS special;
drop COLLATION IF EXISTS numeric;
CREATE COLLATION special (provider = icu, locale = 'en@colCaseFirst=upper;colReorder=grek-latn');
CREATE COLLATION numeric (provider = icu, locale = 'en@colNumeric=yes');
drop COLLATION IF EXISTS special;
drop COLLATION IF EXISTS numeric;
commit;
EOF
第一部分是动态的,第二个 EOF 部分是静态的,相同。我正在尝试寻找一种循环方式。以下是到目前为止我尝试过的。
VAR=$(cat<<EOF
begin;
drop COLLATION IF EXISTS special;
drop COLLATION IF EXISTS numeric;
CREATE COLLATION special (provider = icu, locale = 'en@colCaseFirst=upper;colReorder=grek-latn');
CREATE COLLATION numeric (provider = icu, locale = 'en@colNumeric=yes');
drop COLLATION IF EXISTS special;
drop COLLATION IF EXISTS numeric;
commit;
EOF
)
echo "$VAR"
arr_variable=("/usr/local/pgsql15_1/bin/psql test15" "/usr/local/pgsql14_5/bin/psql test14" "/usr/local/pgsql14_3/bin/psql test14")
for i in "${arr_variable[@]}"
do
echo "$i" "$VAR"
done
有点接近了。预期行为:执行/评估连接字符串。 (如第一个代码块)在终端中。如果可能,当发生错误时,进程退出,打印出错误。
答案1
以下内容避免了必须依赖 shell 正确分割命令字符串。它通过将数据库名称和可执行路径名的唯一部分保存psql
在两个单独的数组中来实现此目的。
#!/bin/bash
statements=$(cat <<'END_SQL'
begin;
drop COLLATION IF EXISTS special;
drop COLLATION IF EXISTS numeric;
CREATE COLLATION special (provider = icu, locale = 'en@colCaseFirst=upper;colReorder=grek-latn');
CREATE COLLATION numeric (provider = icu, locale = 'en@colNumeric=yes');
drop COLLATION IF EXISTS special;
drop COLLATION IF EXISTS numeric;
commit;
END_SQL
)
psql_vers=( pgsql15_1 pgsql14_5 pgsql14_3 )
databases=( test15 test14 test14 )
set -- "${databases[@]}"
for psql_ver in "${psql_vers[@]}"; do
if ! printf '%s\n' "$statements" | "/usr/local/$psql_ver/bin/psql" "$1"
then
break
fi
shift
done
这将创建两个数组,一个用于psql
版本目录,另一个用于数据库名称。
然后,数据库名称将被转移到位置参数列表中,这使得shift
稍后列表中的第一个参数变得微不足道。
在循环中,我们循环遍历psql
版本,对于每个版本,我们以第一个数据库名称作为参数调用相应的可执行文件,在标准输入流上发送 SQL 语句。然后,我们shift
从位置参数列表中删除数据库名称,留下下一个数据库名称$1
以供下一次迭代使用。
循环中管道的退出状态用于判断是否提前终止循环break
。任何输出,无论是错误消息还是其他输出,都会发送到脚本的标准输出和错误流。