スクリプトは次のとおりです。
#!/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
答え2
このIFS
部分を削除してください。
$IFS
はい、内部フィールド区切り変数ですbash
。スクリプトに追加した行のため、フィールドはデフォルト値bash
(スペース、タブ、および改行)ではなく、改行にのみ区別されます。ls
タブ区切りの出力を提供します。
これは働きます:
#!/bin/bash
command="ls /tmp"
for file in `$command`;
do
echo $file
done