3

次のコードがあります

#!/bin/bash
 if [   "-f /data/sb3???sh25t.sqfs" && "! -f /data/sb3??????sh25t.sqfs"  && "! -f /data/sb3????????sh25t.sqfs" && "! -f /data/sb3???????sh25t.sqfs" ]  ;then
      select build in `ls -D /data/tftpboot/sb3???sh25t.sqfs` ; do
         break
      done
    build=${build:15}
 fi

このスクリプトを実行すると、エラーが発生します。

`]'がありません

どうすればこれを解決できますか?

4

4 に答える 4

5

よし、 Jolt Colaの缶を手に入れて座ってくれ。これにはしばらく時間がかかります...

Unix シェルのifステートメントは、コマンド (任意のコマンド) を受け取り、そのコマンドを処理し、そのコマンドがゼロの終了コードを返す場合、 ifステートメントのthen節を実行します。そのコマンドがゼロ以外の値を返す場合、else句があればそれを実行します。

例えば:

if ls foo 2>&1 > /dev/null
then
   echo "File 'foo' exists"
else
   echo "No Foo For you!"
fi

上記はls fooコマンドを実行します。出力は を介し​​てドロップされる2>&1 > /dev/nullため、リストが存在する場合は表示されず、存在しないfoo場合はエラー メッセージが表示さfooれません。ただし、存在する場合はlsコマンドが返され、存在しない場合は a が返されます。0foo1

これにより、あらゆる種類のきちんとしたことができます。

if mv foo foo.backup
then
    echo "Renamed `foo` directory to `foo.backup`"
else
    echo "BIG HORKING ERROR: Can't rename 'foo' to 'foo.backup'"
    exit 2  #I need to stop my program. This is a big problem.
fi

上記のコードでは、新しいディレクトリを作成fooする前に、ディレクトリの名前を に変更しようとしています。おそらくディレクトリが存在しないため、コマンドは失敗します。ディレクトリの名前を変更する権限がない可能性があります。それが何であれ、このステートメントにより、コマンドが成功したかどうかをテストできます。foo.backupfoofoomvifmv

これがifコマンドのすべてです。コマンドを実行し、戻り値がゼロかどうかに応じて、then句を実行する場合と実行しない場合があります。


しかし、特定の条件が存在するかどうかをテストしたい場合はどうすればよいでしょうか? 例えば:

  • というディレクトリはありfooますか?
  • 環境変数の$value値は 3 より大きいですか?

これらのことをテストできるようなコマンドがあればいいと思いませんか? ねえ、私のテストが真の場合にそのコマンドがゼロ値を返し、私のテストが偽の場合にゼロ以外の値を返す場合、それをifステートメントに組み込むことができます!

幸いなことに、Unix にはtestと呼ばれるコマンドがあり、まさにこれを実行します。

if test -d foo
then
    echo "Directory foo exists"
fi

if test $value -gt 3
then
    echo "\$value is bigger than 3"
fi

また、Unix コマンドにコマンドへのtestハードリンク[がある場合もあります。

$ cd /bin
$ ls -li test [
54008404 -rwxr-xr-x  2 root  wheel  18576 Jul 25  2012 [
54008404 -rwxr-xr-x  2 root  wheel  18576 Jul 25  2012 test

最初の列はinode番号です。どちらも同じ inode 番号であるため、[コマンドは単にコマンドへのハード リンクtestです。

これで、物事が少し理解しやすくなりました。1は実際には[Unixコマンドです! そのため、角括弧とテスト対象の間にスペースが必要です。

# Invalid Syntax: I need spaces between the test and the braces:
if [$value -gt 3]

# Valid Syntax
if [ $value -gt 3 ]

# Actually the same command as above
if test value -gt 3

また、単にorではなく、先頭にダッシュが付いている理由がより明確に-gtなります。これは、 andが test コマンドのパラメーターであるためです。-fgtf-gt-f


組み込みのシェルがどのように機能するifか、および[が実際にどのように Unix コマンドであるかをより明確に理解できたので、if ステートメントを見て、問題が何であるかを確認できます。

if [ "-f "/data/sb3???sh25t.sqfs" && "! -f /data/sb3??????sh25t.sqfs"  && \
   "! -f /data/sb3????????sh25t.sqfs" && "! -f /data/sb3???????sh25t.sqfs" ]

まず、次のものがあります。

"-f /data/sb3???sh25t.sqfs"

引用符は、文字列全体をtestコマンドの 1 つのパラメーターにしますが、これは必要なものではありません。-fテストしているファイルとは別のパラメーターが必要です。-fしたがって、引用符からを削除する必要があるため、 testコマンドはそれをパラメーターとして認識します。

if [ -f "/data/sb3???sh25t.sqfs" && ! -f "/data/sb3??????sh25t.sqfs"  && \
   ! -f "/data/sb3????????sh25t.sqfs" && ! -f "/data/sb3???????sh25t.sqfs" ]

これはまだ機能しません。コマンドについては、(man ページ)[http://www.manpagez.com/man/1/test/] を参照してくださいtest&&はコマンドの有効なパラメーターではないことに注意してくださいtest。代わりに、-a2 つの式を組み合わせるために使用することを想定しています_ テスト:

if [   -f "/data/sb3???sh25t.sqfs"      -a ! -f "/data/sb3??????sh25t.sqfs"  -a \
     ! -f "/data/sb3????????sh25t.sqfs" -a ! -f "/data/sb3???????sh25t.sqfs" ]
then

は引用符の-f外にあり (そして も!)、-ato と 4 つの条件すべてを一緒に使用しています。

次のようなこともできます。

if [ -f "/data/sb3???sh25t.sqfs" ]      && [ ! -f "/data/sb3??????sh25t.sqfs" ] && \
   ! -f "/data/sb3????????sh25t.sqfs" ] && [ ! -f "/data/sb3???????sh25t.sqfs" ]

これは、実際にはlist operator&&と呼ばれる bash シェル構造です。2 つの個別のコマンドをリンクし、次のことを行います。

  • 最初のコマンドを実行します。
  • 最初のコマンドがゼロ以外の値を返す場合は、2 番目のコマンドを実行します。それ以外の場合は、最初のコマンドの終了コードを返し、2 番目のコマンドを実行しないでください。

たとえば、次のようなものをよく見かけます。

[ -d foo ] && rm -rf foo

または(同じこと):

test -d foo && rm -rf foo

foo上記のコマンドでは、ディレクトリとして存在するかどうかをテストしています。存在する場合、テスト コマンドは true 値を返し、ディレクトリを削除する 2 番目のコマンドを実行します。それは同じです...

if [ -d foo ]
then
   rm -rf foo
fi

したがって、私のifステートメントは 4 つの個別のコマンドで構成されています。最初の[...]コードが実行され、ファイル/data/sb3???sh25t.sqfsが実際に存在するかどうかが確認されます。そうであれば、そのテストは真であり、ゼロの終了コードを返します。次に、&&リスト内の次のコマンドが実行されます。

次のテスト コマンドは、が存在/data/sb3??????sh25t.sqfs しないかどうかを確認します。そのファイルが存在しない場合、テスト コマンドはゼロの終了コードを返し、次の&&リスト オペレーターが次のテスト コマンドを実行します。最初の 3 つのtestコマンドが true の場合にのみ、最後のテスト コマンドが実行されます。最後のテスト コマンドも真のステートメントである場合、then句が実行されます。


if現在の仕組みと、問題が発生した理由をご理解いただければ幸いです。

悲しいことに、もう 1 つ問題が発生しています。それは、Unix シェルがどのように機能し、グロビングがコマンド ラインとどのように相互作用するかです。

他のオペレーティング システムの対応するものとは異なり (Windows!)、Unix シェルは非常にインテリジェントであり、非常に面倒です。

コマンドラインから次のコマンドを試してください。

$ echo "Print an *"   #Use quotes
Print an *

これを試してください:

$ echo Print an *    #No quotes
Print an bin foo bar...

これにより、すべての「Print an」に続いて、現在のディレクトリ内のすべてのファイルが出力されます。

これを試して:

$ touch foo.out foo.txt
$ echo "Do I have any foo.??? files"
Do I have any foo.??? files
$ echo Do I have any foo.??? files
Do I have any foo.out foo.txt files

繰り返しますが、引用符がなければ、印刷するように依頼したものが変更されました. これは、Unix シェルがおせっかいだからです。何が起こっているかというと、Unix シェルがグロビングパターンを認識し、コマンドが何かをエコーする機会を得る前に、foo.???そのパターンをすべての一致するファイルに置き換えます。echo

これが次のように発生していることを確認できます。

$ set -x   #Turns on `xtrace`
$ touch foo.out foo.txt
+ touch foo.out foo.txt
$ echo "Do I have any foo.??? files"
+ echo "Do I have any foo.??? files"
Do I have any foo.??? files
$ echo Do I have any foo.??? files
+ echo Do I have any foo.out foo.txt files
Do I have any foo.out foo.txt files
$ set +x   #Turns off `xtrace`

この機能は、シェルがコマンドをいじった後xtraceに実行するコマンドを示します。で始まる行は、コマンドが実際に実行する内容を示しています。+

これを取り上げる理由は、考えられる問題によるものです。パターンに一致するファイルが複数ある場合は、パターンに一致するすべてのファイルがテスト コマンドに置き換えられます。もう一度コマンドを見てみましょう。

if [ -f /data/sb3???sh25t.sqfs ] &&        [ ! -f /data/sb3??????sh25t.sqfs ] && \
   [ ! -f /data/sb3????????sh25t.sqfs ] && [ ! -f /data/sb3???????sh25t.sqfs ]

ファイル/data/sb3aaash25t.sqfsと という名前のファイルがある場合/data/sb3bbbsh25t.sqfs、if ステートメントの最初のテスト コマンドは実際には次のようになります。

if [-f /data/sb3aaash25t.sqfs /data/sb3bbbsh25t.sqfs ] 

-fパラメータは単一のファイル名しかとらないため、これは機能しない可能性があります。したがって、上記のすべてを行ったとしても、動作しないプログラムになる可能性があります。さらに悪いことに、断続的に失敗し、デバッグがさらに難しくなります。

これを回避する1つの方法は、 test コマンドを忘れて、lsこの回答の一番上の部分で見たようなコマンドを使用することです:

if ls /data/sb3???25t.sqfs 2>&1 > /dev/null
then
   echo "At least one file that matches pattern sb3???25t.sqfs exists"
fi

したがって、これを行うことができます:

if   ls /data/sb3???sh25t.sqfs       2>&1 > /dev/null && \
   ! ls /data/sb3??????sh25t.sqfs    2>&1 > /dev/null && \
   ! ls /data/sb3????????sh25t.sqfs  2>&1 > /dev/null && \
   ! ls /data/sb3???????sh25t.sqfs   2>&1 > /dev/null
then

ls複数のファイルを取ることができるためです。

説明が長くなってしまい申し訳ありません。99% の確率で、ifステートメントがどのように機能するか、[...]実際には とは完全に別の Unix コマンドであることif、または厄介な Unix シェルがどのようにつまずくかを理解する必要なく、思い通りに進めることができます。

たまたま、この質問で大当たりしただけです。今日、台本を書く代わりに宝くじをプレイしていたら、上司に上司のことを本当にどう思っているかを伝え、仕事を終えて、文化が非常に原始的な熱帯の島の楽園に引っ越すことができたはずです。エミュレータ

代わりに、明日塩鉱山に戻ります。


1はい、はい。[これは BASH シェルに組み込まれており、コマンドではないことはわかってい/bin/[ます。ただし、組み込みのシェルはコマンド[のように機能し/bin/[ます。

于 2013-02-14T20:17:48.790 に答える
0

あなたのコードは次のように書かれたほうがいいです

#!/bin/bash
if [   -f /data/sb3???sh25t.sqfs ] &&
   [ ! -f /data/sb3??????sh25t.sqfs ] &&
   [ ! -f /data/sb3???????sh25t.sqfs ] &&
   [ ! -f /data/sb3????????sh25t.sqfs ]; then
   select build in /data/tftpboot/sb3???sh25t.sqfs ; do
       break
   done
   build="${build:15}"
fi

f(テストしているファイル名のパターンが見やすくなるように、テストを並べ替えました。)

演算子を引用符で囲まない-f(ただし、オペランドを引用符で囲む習慣をつけてください)、各テストを別々のコマンドに入れてください。パターン展開では、選択するファイルのリストがすでに生成されているため、コマンドで実行する必要はありません。そのリストを取得して再現するだけなので、操作は不要です。test/[lsselectls

于 2013-02-14T17:32:26.953 に答える
0

-aの代わりに使用&&し、式の前後に二重引用符を追加しないでください"! -f /filename"-f /data/sb3????????sh25t.sqfsまた、パターンに一致するファイルが複数ある場合は機能しないことに注意してください。

于 2013-02-14T17:15:41.087 に答える
0

また、&&内側に焦げ目があります[ ] これは許可されていません

このよう[[に使用]]または取り出します&&

[ -f file1 ] && [ -f file2 ]

グロブを使用しているため、以下の構文は使用できません。

でも使ったほうがいい

[[ -f file1 && -f file2 ]]

bash後者は詳細情報でのみ機能することに注意してください:

Bash の単純な論理演算子

于 2013-02-14T17:17:15.310 に答える