这个bash脚本有什么问题:
OIFS=$IFS;
IFS=$IFS;
IFS=",";
tables=($1);
len="${#tables[@]}";
if [ $len -eq 0 ]; then
tables=("a,b,c");
fi;
IFS=$OIFS
for ((i=0; i < $len; ++i));
do
echo "table ${tables[$i]}";
done
为什么if [ $len -eq 0 ];
无法评估?如果缺少脚本参数,则设置默认的表列表。请告诉我!
期望的输出 a)带参数:
./test.sh "x,y,z"
table x
table y
table z
b)没有争论:
./test.sh
table a
table b
table c
我真的很抱歉,如果这个剧本冒犯了某人,我真的在这里得到帮助和bash脚本的新手。当他寻求帮助时,他真的很不情愿地推动某人。我以前会想两次将问题发布到&#34; bash&#34;社区。是的,我总是错的,因为我正在寻求帮助,并且善意地来到这里
欢呼声
根据您的建议编辑整个工作脚本
#!/bin/bash
#author: sakhunzai
#usages: usage: ./change_db_engine.sh -h [Show help and exit] -u [dbuser] -p[dbpwd] -d[dbname] -e [engine] [csv tables]
NL=$'\n'
function usage() {
echo "$NL $1 $NL
usage: $0 -h [Show help and exit] -u [dbuser] -p[dbpwd] -d[dbname] -e [engine] [csv tables]
Author:sakhunzai$NL";
exit;
}
while getopts ":hu:p:d:e:" opt; do
case $opt in
'h') usage " *** Usage Help **** ";;
'u') usr=$OPTARG;;
'p') pwd=$OPTARG;;
'd') db=$OPTARG;;
'e') engine=$OPTARG;;
\?)
usage "Invalid arguments '-$OPTARG'" ;;
esac
done
if [ -z $usr ] ; then
usage "-u [dbuser] missing";
fi;
if [ -z $pwd ] ; then
usage "-p [dbpwd] missing";
fi;
if [ -z $db ] ; then
usage "-d [dbname] missing";
fi;
if [ -z $engine ] ; then
usage "-e [engine] missing";
fi;
shift $((OPTIND - 1));
# list of tables to be changes separated by comma
IFS=, read -a tables <<< "$1"
if [ "${#tables[@]}" -eq 0 ]; then
tables=($(mysql -u$usr -p$pwd $db -e"show tables" | tr '\n', ' '));
unset tables[0]
tables=( "${tables[@]}" )
fi;
for ((i=0; i < "${#tables[@]}"; ++i));
do
echo "ALTER TABLE ${tables[$i]} ENGINE = InnoDB; ";
done
肯定会有一些丑陋的代码。
答案 0 :(得分:2)
tables=("a,b,c")
创建一个包含单个元素a,b,c
的数组,不包含三个表名的列表。你想要的是tables=("a" "b" "c")
。
整个脚本可以简化为:
if [ $# -eq 0 ]
then
set -- "a" "b" "c"
fi
for table
do
echo "table $table"
done
当然,使用此功能,您必须使用script.sh foo bar baz
代替script.sh foo,bar,baz
。
答案 1 :(得分:1)
你有一个逻辑问题:你在$len -eq 0
时设置默认表数组,然后在输出数组时,你的循环是i=0; i < $len; ++i
- 这意味着你永远不会看到默认表。您应该将默认值更改为:
if [ $len -eq 0 ]; then
tables=(a b c);
len=3;
fi;
答案 2 :(得分:1)
当您可以提供帮助时,请不要在全球范围内设置IFS
。请改用:
IFS=, read -a tables <<< "$1"
len="${#tables[@]}"
if [ $len -eq 0 ]; then
tables=(a b c);
fi
for t in "${tables[@]}"
do
echo "table $t"
done
答案 3 :(得分:1)
你问“出了什么问题?”这是:
OIFS=$IFS; # Lots of unnecessary semicolons
IFS=$IFS; # This does nothing.
IFS=",";
tables=($1); # Why jump through hoops to redo wordsplitting? Something smells off with this, like you're making it too complicated.
len="${#tables[@]}";
if [ $len -eq 0 ]; then
我可能会在这里做if (( !$len )); then
,但这并没有什么问题。
tables=("a,b,c");
即使您删除了引号,也无法执行此操作。以下是手册对IFS
所说的内容:
内部字段分隔符,用于在扩展后进行单词拆分,并使用read builtin命令将行拆分为单词。默认值为
<space><tab><new-line>
。
关键词是“扩张后”。即使删除引号,该值也将是一个包含单个元素“a,b,c”的数组。您可以使用foo='a,b,c'; tables=($foo)
强制扩展,但这是非常人为的。你真正想要的是tables=(a b c)
。
fi;
IFS=$OIFS
for ((i=0; i < $len; ++i));
我会写这个for i in "${!tables[@]}"; do
。这将遍历任何现有的数组键,而不是手动构建您希望存在的键列表。考虑bash数组是稀疏的。还要考虑你正在跳过第0个元素。
do
echo "table ${tables[$i]}";
done
我认为整个循环可以重写printf table %s\n' "${tables[@]}"
,但也许你需要它用于其他目的。
我没有看到任何阻止表长度测试按预期工作的内容。实际上,如果您为脚本提供任何的参数,则该值将为非零值。如果给脚本没有参数,则该值将为0,并且if
块将发生。
但是,由于你在循环中跳过了第0个参数,如果tables数组只有一个值,它就永远不会打印出来。
我没有足够的上下文来批评逗号分隔,但它似乎过于复杂。您在l0b0's answer中的评论让我觉得您应该让脚本采用标准输入。 (您也可以使用mysql
,mapfile
或xargs
将paste
输出转换为可能比使用tr
更有效的参数,但我认为{{1}将是最好的选择。)