
スクリプトを作成しましたが、実行すると、次のような結果が表示されます。
./autotex: line 7: syntax error near unexpected token `then'
./autotex: line 7: ` then'
スクリプトは次のとおりです。
#!/bin/bash
while [ $key = "q"]; do
dateTex = grep $1.tex| cut -b 43 - 54
datePdf = grep $1.pdf| cut -b 43 - 54
if[$dateTex !eq $datePdf]
then
pdflatex $1.tex
fi
read -t 1 -n 1 key
done
答え1
while [ $key = "q"]; do
しなければならない
while [ $key = "q" ]; do
そして
if[$dateTex !eq $datePdf]
しなければならない
if [ "$dateTex" != "$datePdf" ]
言及する必要がない
dateTex = grep $1.tex| cut -b 43 - 54
別の同様の行が壊れて、次のように表示されます。
dateTex=$(grep something $1.tex | cut -b 43-54)
答え2
重要な問題
他の多くのプログラミング言語とは異なり、Bourneシェル構文には、特定の場所の空白に関連する特定の特性があります。混乱する部分は次のとおりです。
[
これが次のようなことを覚えておくことが重要です。注文する、]
最終的な文法的特徴(脚注1)ではありません。ディスカッションこのコマンドで。
Bourne(および類似/派生)シェルでは、スペース(脚注2)はコマンドとその引数を区別し、//while
キーワードは実際にこれらのキーワードに続くすべてのコマンドを呼び出し、戻り値に対して機能します。if
until
Bourneシェルの別の珍しい属性(コード内の問題のように見える)は、スペースに固有の変数割り当てです。いいえ変数名、記号、=
および割り当てられた内容の間のスペース。
さらに、コマンドの出力はほとんどの言語のように自動的に変数に入りません。これには「コマンドの置き換え」を使用する必要があります。新しくネスト可能で、より広く推奨される構文は$(command to run)
(脚注3)です。
コードの例
したがって、上記の内容をコードに適用してください。
while [ $key = "q"]; do
..問題はです"q"]
。シェルはこれをtest
/コマンドの[
引数として扱います。 (q]
引用符はここでも何もしません。シェルには変数型はありません。一部のコンテキストを除いてすべてが文字列なので、すでにq
文字列 - 特殊文字をエスケープするための引用符)私はこれを次のように修正します。
while [ "$key" = q ]; do
..また、$key
常に正しく解釈されるように引用します(脚注4)。ここでも同じ問題(および別の問題)が発生します。
if[$dateTex !eq $datePdf]
..シェルはスペースを使用して、ある項目が終わり、別の項目が始まる場所を教えてくれることを覚えておいてください(再度、脚注2)。と言うと、最初にgettingにif[$some_var
置き換えられ、次にコマンドの名前を実行しようとします。したがって、まずスペースを使用する必要があります。$some_var
some_text
if[some_text
if[some_text
if
[
これこれがthen
コードがエラーを印刷する理由です。 bashはを見た後にのみaを期待しますif
が、決して見ずにまったく別のコマンド/トークンに解析されることをif
見ます。if[$dateTex
、とを[
区別するためにスペースを使用する理由も同じ原理です。$dateTex
$datePdf
]
最後に、!eq
コマンド認識の[
ための有効な引数/テストではありません。周囲の引数を整数として解釈し(引用符にかかわらずコマンドを-eq
入力するシェルに関する限り、文字列です)、同じかどうかを比較します。[
否定演算子に対するあなたの考えは正確です!
が、シェルの他の多くの項目と同様に、[
他のパラメータの前に別々のパラメータでなければなりません。だからあなたは欲しい:
if [ ! "$dateTex" -eq "$datePdf" ]
..またはコマンドの代わりにシェルの否定演算子を使用することができます[
(スペースにもう一度注意してください。シェル構文がスペースに分割されている場合は、別のトークン/フィールドでなければなりません)。
if ! [ "$dateTex" -eq "$datePdf" ]
また、他の回答によれば、=
2つのパラメータ文字列が同じであることを確認し(比較する前にパラメータ文字列を整数として解釈するのではなく)、2つの文字列が異なるかどうかを確認する-eq
特殊なケース否定演算子もサポートされています。!=
ユースケースで文字列比較で十分な場合は、次のいずれかを使用できます。
if [ "$dateTex" != "$datePdf" ] # != operator
if [ ! "$dateTex" = "$datePdf" ] # test ! operator with test = operator
if ! [ "$dateTex" = "$datePdf" ] # shell ! operator with test = operator
次に、変数の割り当てを含む次の行に移動します。
dateTex = grep $1.tex| cut -b 43 - 54
datePdf = grep $1.pdf| cut -b 43 - 54
まず、シェルが解析する方法は、拡張内容に応じて引数と1つ以上の引数を使用してコマンドを実行することです(再び脚注4)dateTex = grep $1.tex
。したがって、2番目にこのコマンドの場合、オプションはリストを1つの引数として使用するため、スペースなしで1つにマージしたいと思います。とにかくコマンド置換を使用したいと思うので、次のようなことをしたいと思います。dateTex
=
grep
$1
$1
cut
-b
43-54
dateTex=$(grep "$1".tex | cut -b 43-54)
..そして他の行にも同じことをします。最後にgrep filename
何か間違っているようです。grep
最初の引数(オプション以外)は検索/一致するパターンでなければなりません。したがって、サンプルコードにこれを書くと、stdinが読み込み、拡張"$1".tex
パターンを検索します。おそらくファイル内の"$1".tex
どのパターンを検索したいのか、これを行う必要がありますgrep pattern "$1".tex
。
これをすべて実行した後、実際のコードが投稿したコードと異なるか、またはそれ以上のエラーメッセージが表示されると思われます。
脚注
[1]このコマンドはでtest
あり、[
コマンドを呼び出すことができる別の名前です。唯一の違いは、呼び出し時に最後の引数が予想されることです。技術的には、ほとんどの実装では組み込みシェルですが、構文規則は同じです。test
]
]
[2]技術的にはIFS
(内部フィールド区切り文字)変数のすべてですが、通常は空白、タブ、および改行です(改行は他の理由で少し特別です)。
[3]古いが入れ子になっていない構文は`command to run`
- 非常に古いか、やや非標準的なシェル(たとえばSolaris 10 /bin/sh
)でスクリプトを実行したい場合、個人的にはこの構文はとても良いと思いますが、そうではありません。スクリプトにネストが必要だと思います(新しい構文の唯一の実際の利点)。しかし、インタラクティブなコマンドラインの使い方を簡単にする方法がわかります。
[4]変数を引用符で囲まないと、$IFS
変数が置き換えられた後、変数のスペース(または脚注1のすべての項目)が評価され、行全体で「フィールド分割」が再実行されます。したがって$key
、設定されていない場合は空白または単にただ引用符のない空白文字は、デフォルトでコマンドから「消えます」。インクルードなどのブレンドがある場合は、$key
それを追加すると2つのパラメータabc def
の合計になります。同じ原則が代替項目を含む行全体に適用されます。したがって、インクルードとコマンドラインがある場合、シェルは文字列を次に分割します(1つの引数でコマンドを実行)。変数が参照されている場合、これは発生しません。abc
def
$key
abc def
foo$keybar
fooabc defbar
fooabc
defbar
"$key"