작고 간단한 스크립트가 "해당 파일이나 디렉터리가 없습니다"라는 출력과 함께 실패합니다.

작고 간단한 스크립트가 "해당 파일이나 디렉터리가 없습니다"라는 출력과 함께 실패합니다.

스크립트는 다음과 같습니다

#!/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가 변수에 대해 올바르게 수행하지 않는다는 것입니다. 이로 인해 첫 번째 단어를 명령으로 전달하고 나머지 단어를 인수로 전달하는 대신 전체를 하나의 명령으로 실행하려고 합니다.

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

관련 정보