web-dev-qa-db-ja.com

関数にディレクトリ名を渡そうとすると「is a directory」エラー

私のbashスクリプトでは、findを使用して、ワイルドカードでフォルダー名を取得します。

for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard});
do
  stuff=doStuff ${i}
done

doStuff() {
  echo ${1}
  return ${1}'/hello';
}

問題は、これを実行すると次のエラーが発生することです($ {i}が 'home/me/my_directory'に対応しているとしましょう)。

line 111: '/home/me/my_directory': is a directory. 

(111行目は「doStuff」のある行です)

私はこれをやってみましたが、役に立ちません:

for i in $(find ${directory} -mindepth 1 -type d -name ${wildcard});
do
  stuff=doStuff "${i}"
done

どうやら、それはプログラムがディレクトリを実行しようとしているためですが、操作できる文字列としてそれを必要としています。

5
user2205763

ここでは、引用とコマンド置換が問題になります。

実行している特定の問題は、シェルが環境変数_/home/me/my_directory_を使用して_stuff=doStuff_というコマンドを実行しようとしているためです。
あなたが本当に望んでいること(私が正しく解釈している場合)は、_$i_の値を引数としてdoStuffを実行し、変数stuffに出力を割り当てます。これを行う方法は、コマンドを$()でラップすることです。例えば:

_stuff="$(doStuff "$i")"
_

すべてを引用符で囲む方法にも注意してください。これは、シェルが不要なものをWordに分割しないようにするためです(_/foo/bar baz_の単一の引数を_/foo/bar_とbazに変換します)。

また、関数の出力は、returnではなく、戻り値として使用されるものです。

より多くの引用符を使用する必要があるため、他のすべてに引用符を追加する必要もあります。ここにあなたのスクリプトの完全なバージョンがあります:

_doStuff() {
  echo "${1}" >&2
  printf '%s/hello' "$1";
}

IFS=$'\n'
for i in $(find "${directory}" -mindepth 1 -type d -name "${wildcard}");
do
  stuff="$(doStuff "${i}")"
done
_

使用してみる前に、関数定義を配置する必要があります。シェルは、コンパイルされたプログラムのように解析されず、ファイルを何度も通過します。それはトップダウンです。
また、doStuffを変更して、echoを端末に表示するSTDERRに送信し、printfをSTDOUTに送信して、変数stuffにキャプチャします。

ディレクトリのいずれかに改行が含まれている場合でも、問題が発生することに注意してください。ただし、これはシェルの制限です。ファイルパスに含めることができない唯一の文字はNULL文字(_\0_)です。ただし、bashやその他のシェルでは文字列にNULL文字を格納できないため(すべてではないが、多くの場合zshは可能です)、区切り文字として使用することはできません。

7
Patrick

これはかなりの努力ですが、実際には単純なスクリプト言語であるにもかかわらず、bashをプログラミング言語のように書こうとしていることを示しています。あなたのstuff=doStuff arg構造の問題は、bashにとってそれがあなたがそれが何を意味するかを意味しないということです。 bashに対して、stuff=doStuffは変数の割り当て、argはコマンドです。次の2つのリンクを読むことをお勧めします。

あなたが持っているものに似たものの作業バージョン

doStuff () {
    echo "$1/hello"
}

stuff=$(doStuff "$i")
3
jw013

エラーを示す行は、あなたが思っていることをしていません:

最初に環境変数を文字列 "doStuff"に設定し、次に$ {i}をコマンドとして実行しようとします。また、$ {i}はディレクトリであるため、指定されたエラーメッセージで失敗します。

1
daniel kullmann