Bash将值与零进行比较

时间:2014-03-13 14:48:17

标签: linux bash

这个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

肯定会有一些丑陋的代码。

4 个答案:

答案 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中的评论让我觉得您应该让脚本采用标准输入。 (您也可以使用mysqlmapfilexargspaste输出转换为可能比使用tr更有效的参数,但我认为{{1}将是最好的选择。)