web-dev-qa-db-ja.com

commはbash変数入力で失敗します

2つのディレクトリのファイルのリストを取得し、違いを取得して、特定のファイルに対していくつかのコードを実行することになっているスクリプトがあります。

ファイルリストを取得するためのコマンドは次のとおりです。

list_in=$(find input/ -maxdepth 1 - type f | sed 's/input\///' | sort -u);
list_out=$(find output/ -maxdepth 1 - type f | sed 's/output\///' | sort -u);

正しいディレクトリでスクリプトを実行するので、これは失敗しないはずです。未処理のファイルはによって決定されます

list_todo=$(comm -23 <(echo "$list_in") <(echo "$list_out"));

オプション-23 for commは最初の引数の行のみを出力するため、両方の引数に表示されず、2番目の引数に一意に表示される行も出力されません。

ただし、たまにしかエラーが発生します

command substitution: line 3: syntax error near unexpected token `('
command substitution: line 3: `comm -23 <(echo "$list_in") <(echo "$list_out")'

まったく同じスクリプトが過去3週間うまく機能したので、これは本当に私を困惑させます。これをクラスターで使用しているため、複数のプロセスがスクリプトを同時に実行する可能性があります。これが原因でエラーが発生する可能性がありますか?

更新。スクリプトは./scriptで呼び出され、私は明らかに以前にchmod +x scriptを設定しました。

(免責事項:クラスターで作業していて、スクリプトの最初の3行にロックメカニズムが含まれていない場合でも、もちろん、ファイルが2回処理されることはありません)

3
stefan

カーネルは、ネイティブに実行できる特定のファイル形式を認識します。これには、少なくとも1つのバイナリ形式が含まれます。さらに、#!Shebang )で始まるファイルはスクリプトと見なされます。たとえば、ファイルが/path/to/scriptにあり、#!/bin/bashで始まる場合、カーネルは/bin/bash /path/to/script arg1 arg2を呼び出すと/path/to/script arg1 arg2を実行します。

カーネルがファイル形式を認識しない場合、 execve システムコールからENOEXEC(exec形式エラー)を返します。 Shebang機能を備えていなかったUnixカーネルの古代からの伝統に従い、ほ​​とんどのプログラムは、最初の試行がエラーENOEXECで失敗したときに、プログラムの実行を2回試行します。/bin/shをスクリプトインタプリタ。

Bashは注目すべき例外です。スクリプトは、/bin/shではなく、それ自体で実行されます。したがって、bashからスクリプトを呼び出したときに、スクリプトが誤って機能していました。

Shebang行を省略した場合、スクリプトは、実行元のプログラムに応じて、/bin/bashまたは/bin/shで実行される可能性があります。そして、/bin/shは明らかにあなたのシステムでのプロセス置換をサポートしていません。おそらくまだbashです(エラーメッセージはbashからのもののように見えます)が、bashがshという名前で呼び出されると、プロセス置換をサポートしないPOSIX互換モードになります。

話の教訓:bashスクリプトを作成する場合は、最初の行に#!/bin/bashを配置する必要があります。

$()および<()構文はbashのみです。つまり、シバンラインは次のようにする必要があります。

#!/bin/bash

特にこれはnot動作します:

#!/bin/sh

shで動作する必要がある場合は、$()の代わりに `を使用できます。

list_in=`find input/ -maxdepth 1 - type f | sed 's/input\///' | sort -u`

<()の代わりにmkfifoを使用できます。

1
Ole Tange