コンパクトでシンプルなスクリプトは、「ファイルやディレクトリはありません」という出力で失敗します。

コンパクトでシンプルなスクリプトは、「ファイルやディレクトリはありません」という出力で失敗します。

スクリプトは次のとおりです。

#!/bin/bash
IFS="
"

command="ls /tmp"

for file in `$command`;
do
    echo $file
done

出力は次のとおりです

$ ./test.sh 
./test.sh: line 17: ls /tmp: No such file or directory

ベストアンサー1

問題は、空白を含む変数を$IFS改行文字に設定したため、bashが変数に対して正しく実行されないことです。これにより、最初の単語をコマンドとして渡し、残りの単語を引数として渡すのではなく、全体を1つのコマンドとして実行しようとします。

strace以下が表示されるのではなく、このコマンドを実行したい場合:

execve("/bin/ls", ["ls", "/tmp"], [/* 42 vars */]) = 0
                   ---    -----
                    |       |-------------> 2nd argument 
                    |---------------------> 1st argument, the command to run.

ls /tmp最初のパラメータが単独ではないことがわかります。lsこれはシステムができないことです。

変数を設定しないと、スクリプトは実際に期待どおりに機能しますIFS。ただし、実際にlsはiterateコマンドの出力を使用しないでください。知る出力にはスペースやその他の奇妙な文字は含まれません。表示するには:

$ touch 'file name with spaces'
$ for i in $(ls ./); do echo "$i"; done
file
name
with
spaces

正しい方法は、次のいずれかを使用することです。

$ for i in *; do echo "i is: $i"; done
i is: file name with spaces
$ find . -type f | while IFS= read -r i; do echo "i is: $i"; done
i is: ./file name with spaces

本当に使いたい場合は、ls少なくともwhileループで使用してください。いくつかの理由でまだ機能していませんが、少なくともスペースを処理することはできます。

$ ls | while read i; do echo "i is: $i"; done
i is: file name with spaces

最後に、対処できるどの改行、バックスラッシュ、スペースなどを含むファイル名。使用:

  $ find . -type f -print0 | while IFS= read -r -d '' i; do echo "i is: $i"; done
  i is: ./file name with spaces

おすすめ記事