0

このスクリプトを実行すると:

#!/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'

私は他の有無にかかわらず試しましたが、問題を見つけることができないようです。ありがとう

4

5 に答える 5

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

(あなたがしたように a をループすることは、非常に悪いbashの習慣と考えられcatています)。[[ -n "$srv" ]]空行を無視するには、ガードを含める必要がありました。コメントを処理したい場合は、ここにもっと洗練されたものを追加できます...

ファイルがハイフンで始まる場合に備えて、にも追加--しました。それは混乱します(それはオプションだと思います)。これは、非常に優れたシェル プラクティスと見なされます。scp$locfilescp

あなたがproduction environmentに言及しているように、私はそうすると思いました。(本番環境で使用されているスクリプトを見るのが怖いことがよくあります)。

実際、問題は[...]as に安全に含めることができるため、ここでは必要ありません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 プログラムを思い起こさせますか?)。代わりに、スクリプトに引数を使用することを検討する必要があります (演習は読者に任せます)。

ディレクトリかどうかをテストすることで、ディレクトリとファイルの問題を完全に取り除くことができます$locfile。(verbose) オプションを使用して、echoどのファイルがscpingであるかを示す を取り除きます。-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

(彼女はタブでファイル名補完を使用できるため)、スクリプトを呼び出すのではなく.

お役に立てれば!

于 2012-12-24T14:33:26.607 に答える
3

それ以外の:

if [-n $answer] then

「[」の後と「]」の前に空白を使用します。同じ行で「then」を使用する場合は、次を使用します;

if [ -n $answer ]; then

または:

if [ -n "$answer" ]
then
于 2012-12-25T08:23:50.180 に答える
2

それ以外の

if [-n $answer] then

試す

if [ -n $answer ]
then

つまり、括弧内にスペースを使用thenし、別の行に置きます。

于 2012-12-24T13:58:09.637 に答える
1

[はコマンドなので、空白を尊重する必要があります。

if [ -n $answer ]; then

のようにcat-n fileまたはecho-e foo有効ではありません。

$ which [
/usr/bin/[
于 2012-12-24T13:58:17.577 に答える
1

それに加えて、常にシェル変数を引用符で囲むので、代わりにtest -n使用してください。if [ -n "$answer" ]; then

于 2012-12-24T14:01:07.407 に答える