我写了这个脚本,但似乎我错过了一些语法

时间:2012-12-24 13:52:52

标签: bash

当我运行此脚本时:

#!/bin/bash
#This script distributes file/folders to all POP servers within the production environment.
echo "Are you willing to transfer a file or a directory? [Answer: file/dir]"
read answer
echo "Please enter a file name or a full path to the files/directories you want to distribute"
read locfile
echo "Please enter the destination path"
read destfile
if [-n $answer] then
        case "$answer" in
                file)
                        for srv in `cat ~/srv.lst`;
                        do echo "$srv:";
                        /usr/bin/scp $locfile $srv:$destfile;
                        done
                ;;
                dir)
                        for srv in `cat ~/srv.lst`;
                        do echo "$srv:";
                        /usr/bin/scp -r $locfile $srv:$destfile;
                        done
                ;;
                *)
                echo "Please check your input"
esac
fi

我得到了这个输出:

./distribute_files: line 26: syntax error near unexpected token `fi'
./distribute_files: line 26: `fi'

我尝试过或不尝试其他但我似乎无法找到问题。 感谢

5 个答案:

答案 0 :(得分:3)

我使用bash惯用语重写了你的脚本:

#!/bin/bash

#This script distributes file/folders to all POP servers within the production environment.

echo "Are you willing to transfer a file or a directory? [Answer: file/dir]"
read -r answer
echo "Please enter a file name or a full path to the files/directories you want to distribute"
read -r locfile
echo "Please enter the destination path"
read -r destfile

if [[ -n "$answer" ]] then
    case "$answer" in
        file)
            while read -r srv; do
                [[ -n "$srv" ]] || continue
                echo "$srv:"
                /usr/bin/scp -- "$locfile" "$srv:$destfile"
            done < ~/srv.lst
            ;;
        dir)
            while read -r srv; do
                [[ -n "$srv" ]] || continue
                echo "$srv:"
                /usr/bin/scp -r -- "$locfile" "$srv:$destfile"
            done < ~/srv.lst
            ;;
        *)
            echo "Please check your input"
            ;;
    esac
fi

发生了什么变化?更多的引用(当文件名包含空格时,您的脚本迟早会崩溃)并使用[[...]]而不是弃用且不太健壮(在bash中)[...]。我还使用read-r选项(因为不允许反斜杠转义任何字符)。我也改变了

for svr in `cat ~/srv.lst`; do

进入更成熟的

while read -r srv; do
    ...
done < ~/src.lst

(它真的被认为是非常糟糕的bash练习,就像你一样循环cat。我不得不包括一个警卫[[ -n "$srv" ]]来忽略空行。如果想要处理评论,你可以在这里添加更复杂的东西......

我还将--添加到scp,以防文件$locfile以连字符开头。这会让scp感到困惑(它会认为这是一种选择)。这被认为是非常好的贝壳练习。

当我提到生产环境时,我想我会这样做。 (我经常害怕看到生产中使用的脚本)。

事实上,您的问题是关于此处不需要的[...],因为您可以安全地将其包含在case中:

#!/bin/bash

#This script distributes file/folders to all POP servers within the production environment.

echo "Are you willing to transfer a file or a directory? [Answer: file/dir]"
read -r answer
echo "Please enter a file name or a full path to the files/directories you want to distribute"
read -r locfile
echo "Please enter the destination path"
read -r destfile

case "$answer" in
    "")
        true
        # Do whatever you like here
        ;;
    file)
        while read -r srv; do
            [[ -n "$srv" ]] || continue
            echo "$srv:"
            /usr/bin/scp -- "$locfile" "$srv:$destfile"
        done < ~/srv.lst
        ;;
    dir)
        while read -r srv; do
            [[ -n "$srv" ]] || continue
            echo "$srv:"
            /usr/bin/scp -r -- "$locfile" "$srv:$destfile"
        done < ~/srv.lst
        ;;
    *)
        echo "Please check your input"
        ;;
esac

此外,像你这样的“交互式”脚本被认为是不好的做法(这让人联想到旧家庭计算机上的旧BASIC程序吗?)。您应该考虑使用脚本的参数(练习留给读者)。

你可以完全摆脱dir v.s.文件,通过测试$locfile是否为dir。并使用echo(详细)选项摆脱scp告诉-v哪个文件:

#!/bin/bash

#This script distributes file/folders to all POP servers within the production environment.

read -r -p "Please enter a file name or a full path to the files/directories you want to distribute" locfile
read -r -p "Please enter the destination path" destfile

ropt=""
if [[ -d "$locfile" ]]; then
    ropt='r'
fi

while read -r srv; do
    [[ -n "$srv" ]] && /usr/bin/scp -v$ropt -- "$locfile" "$srv:$destfile"
done < ~/srv.lst

事实上,我越看看你的脚本做什么,我认为用户输入终端的速度就越快:

$ while read -r srv; do [[ -n "$srv" ]] && /usr/bin/scp -v "myfile" "$srv:mydestfile"; done < ~/srv.lst

(因为她可以使用标签使用文件名完成),而不是调用你的脚本。

希望这有帮助!

答案 1 :(得分:3)

而不是:

if [-n $answer] then

在&#39; [&#39;之前&#39;]&#39;。如果你想使用&#39;那么&#39;在同一行中使用;

if [ -n $answer ]; then

或者:

if [ -n "$answer" ]
then

答案 2 :(得分:2)

而不是

if [-n $answer] then

if [ -n $answer ]
then

也就是说,在括号中使用空格,并将then放在不同的行上。

答案 3 :(得分:1)

[是一个命令,所以你需要尊重空白:

if [ -n $answer ]; then

就像cat-n fileecho-e foo无效一样。

$ which [
/usr/bin/[

答案 4 :(得分:1)

除此之外,请始终在test -n中引用您的shell变量,因此请改用if [ -n "$answer" ]; then