我正在尝试在while循环中递增变量值,但我想将它递增两次。 “两次”我的意思是第一次增加变量值,然后做一些操作,然后再增加已增加的值,这都是在while循环中。我的代码如下所示:
i=1
setglobal="SET GLOBAL "
while [ $i -le $# ]
do
assign=$setglobal$i=$($i+1)
START=`date +%s`
mysql $database -u $user -se "$assign;select
here goes my database query, not important"
END=`date +%s`
echo $END - $START | bc>>output.txt
i=$(($i+1))
mysqld restart
done
我有一个发送到我的shell的参数列表:innodb_change_buffer_max_size 16 key_buffer_size 1431655770,分别作为第1,第2,第3和第4个参数。所以我想要while循环:
SET GLOBAL innodb_change_buffer_max_size = 16
之后
assign=$setglobal$i=$($i+1)
和
SET GLOBAL key_buffer_size = 1431655770
之后
i=$(($i+1))
assign=$setglobal$i=$($i+1)
结果,在我的output.txt中,我应该得到每个查询的运行时间,但是我只得到四个零。所以我想我的循环要么没有正确地执行“SET GLOBAL key_buffer_size = 512”这一部分,要么它没有做正确的增量。谁能告诉我我的代码可能有什么问题?
答案 0 :(得分:1)
我相信mysql可以从stdin读取命令,比a更具可读性 单双引号。
while (( $# > 1 )); do
var=$1
val=$2
shift 2
start=$SECONDS
mysql $database -u $user -s <<ENDSQL
SET GLOBAL $var=$val;
select ...
ENDSQL
echo $(( $SECONDS - $start )) >> output.txt
mysqld restart
done
如果你有bash 4,我会处理这样的论点:
declare -A vars
while (( $# > 1 )); do
vars[$1]=$2
shift 2
done
foreach var "${!vars[@]}"; do
start=$SECONDS
mysql $database -u $user -s <<ENDSQL
SET GLOBAL $var=${vars[$var]};
# ... rest is the same
done
假设您可以在一个会话中设置多个sql全局:
sql_commands=()
while (( $# > 1 )); do
sql_commands+=( "SET GLOBAL $1=$2;" )
shift 2
done
sql_commands+=( "select ... from ... where ...;" )
start=$SECONDS
printf "%s\n" "${sql_commands[@]}" | mysql $database -u $user -s
echo $(( $SECONDS - $start )) >> output.txt
mysqld restart
答案 1 :(得分:1)
glenn jackman's helpful answer提供bash
解决方案。
但是,鉴于您通常标记了问题shell
并且您的代码似乎只使用符合POSIX的功能(错误除外),我认为您正在寻找符合POSIX标准的解决方案:
#!/bin/sh
# Make sure that parameters were passed and that they were passed in pairs.
if [ $# -eq 0 ] || [ $(( $# % 2 )) -ne 0 ]; then
echo "ERROR: Please pass parameters in pairs, and pass at least one pair." >&2
exit 2
fi
while [ $# -gt 0 ]; do # Continue while arguments remain.
# Store the (next) pair of parameters in variables.
name=$1
val=$2
shift 2 # Remove the (next) 2 positional parameters from the start of the array.
# Synthesize the mysql SET statement.
assign="SET GLOBAL $name=$val"
# Get start timestanp (resolution in seconds).
start=$(date +%s)
# Invoke the mysql command.
mysql $database -u $user -se "$assign;select
here goes my database query, not important"
# Get end timestamp.
end=$(date +%s)
# Calculate the execution time span and append it to the output file.
echo $(( end - start )) >>output.txt
# Restart mysql.
mysqld restart
done
至于您尝试过的内容:
$($i+1)
无法作为对$i
位置参数的引用:
$(...)
是命令替换(现代等效于`...`
),$i+1
的扩展结果实际上会被解释为命令执行,这不是意图。仅使用POSIX功能,没有直接通过 index 引用位置参数的方法。
bash
中您可以使用${@:i:1}
,但这是非标准扩展名。)因此,最简单的方法是在将值保存在变量中后,使用shift
消耗位置参数(从参数数组的开头删除它们),以及然后检查是否有[ $# -gt 0 ]
。这也消除了对辅助索引变量$i
的需求。
虽然echo $END - $START | bc
有效,但不需要涉及外部实用程序bc
,因为简单的算术扩展$(( END - START ))
就可以了。
最好避免变量名称,例如$START
和$END
,因为全大写的shell变量名称可以conflict with environment variables and special shell variables。