Bash에서 추가가 제대로 작동하지 않습니다.

Bash에서 추가가 제대로 작동하지 않습니다.

">>" 연산자가 내 스크립트에서 제대로 작동하지 않는다는 것을 알았는데 그 이유는 모르겠습니다. 다음과 같은 스크립트가 있습니다.

for file in $(ls folder)`
do
  echo $file >> text.txt
done

입력하다폴더91개의 요소가 있지만 처음 87개의 요소만 삽입했습니다.파일.txt. 이 코드에 어떤 문제가 있는지 알 수 없습니다. 이해하도록 도와주실 분 계신가요?

편집하다

내가 쓴 대본은 매우 간단했지만 상황을 명확하게 설명하지 못한다는 것을 알았습니다. 자세한 내용은 다음과 같습니다.

내 폴더에는 91개의 csv 파일이 있으며 각 파일에는 이름과 값이라는 두 개의 열이 포함되어 있습니다. 각 파일에 대해 값이 2.500보다 큰지, 0.000이 아닌지 제어해야 합니다. 이 두 조건 중 하나가 true이면 삭제한 파일이 포함된 txt 파일에 파일 이름과 해당 값을 추가하고, 그렇지 않으면 선택한 파일이 포함된 csv 파일에 파일 이름과 해당 값을 추가합니다. 값을 제어하는 ​​데 사용하는 코드는 잘 작동하지만 >>를 사용하여 결과를 txt 또는 csv 파일에 추가하면 마지막 4개의 결과가 추가되지 않고 이유를 이해할 수 없습니다.

for file in $(ls folder)
do
     value=$(cat path/$file | awk -F, '{print $2}')
     discard=$(awk -v num1="$value" 'BEGIN { if (num1 > 2.500) print 1; else if (num1 == 0.000) print 0; else print 2 }')

     if [[ $discard -eq 1 || $discard -eq 0 ]]
     then
          echo ""$file" has value="$value"" >> path/discard.txt
          rm path/"$file"
     else
          echo ""$file",$value" >> path/selected.csv
          rm path/"$file"
     fi
done

여기 내 스크립트의 더 완전한 버전이 있습니다.

편집 2

발견한 문제를 해결하기 위해 스크립트를 수정했습니다. 여전히 같은 문제입니다. 더 명확하게 말하면 내 폴더의 파일은 프로그램에 의해 자동으로 생성된 csv 파일이며 ID와 부동 소수점 값이라는 하나의 행과 2개의 열만 포함합니다. 그것들은 모두 매우 유사하므로 터미널에서 스크립트가 이를 인식하고 잘 처리하는 것을 볼 수 있으므로 문제는 없습니다. 나는 왜 추가가 마지막 4개 파일을 txt 파일에 넣지 않는지 아직도 모르겠습니다.

for file in folder/*
do
     value=$(cat "$file" | awk -F, '{print $2}')
     discard=$(awk -v num1="$value" 'BEGIN { if (num1 > 2.500) print 1; else if (num1 == 0.000) print 0; else print 2 }')

     if [[ "$discard" -eq 1 || "$discard" -eq 0 ]]
     then
          echo ""$file" has value="$value"" >> path/discard.txt
          rm -- "$file"
     else
          echo ""$file",$value" >> path/selected.csv
          rm -- "$file"
     fi
done

파일 수를 줄이면 정상적으로 작동합니다.

답변1

여기에는 두 가지 주요 문제가 있습니다.

  1. 절대 하지 않을 것입니다 for file in $(ls). 이것은 또한배쉬 트랩 번호 1. 첫째, 깨지기 쉬우며 보시다시피 약간 이상한 파일 이름이라도 손상될 수 있습니다. 더 나쁜 것은 전혀 필요하지 않으며 코드를 필요한 것보다 더 취약하고 복잡하게 만든다는 것입니다. 당신은 이것을 할 수 있습니다 for file in *.

  2. 항상 변수를 인용하세요. 이는 다음을 포함할 수 있는 파일 이름을 처리할 때 특히 중요합니다.어느문자 제외 \0. 그리고 /. 변수를 인용하지 않으면 쉘이 변수를 확장하므로 공백이 포함되어 있으면 쉘은 하나가 아닌 두 개의 값을 보게 됩니다. 예를 들어:

이를 설명하기 위해 다음 두 파일이 포함된 디렉터리를 생각해 보세요.

$ touch 'a file2' 'file1 *'
$ ls -l
total 0
-rw-r--r-- 1 terdon terdon 0 Sep 22 17:39 'file1 *'
-rw-r--r-- 1 terdon terdon 0 Sep 22 17:39 'a file2'

이제 원본 코드를 시험해 보면 다음과 같은 결과를 얻을 수 있습니다.

$ for file in $(ls); do echo $file; done
a
file2
file1
a file2
file1 a file2 file1 *

이는 참조가 없기 때문에 쉘이 a, file2, 다음 file1을 수신하기 때문입니다 *. 따라서 각 파일을 개별적으로 처리하고 echo *마지막에 실행될 때 디렉터리의 모든 내용을 다시 인쇄합니다. 그러나 올바른 방법으로 수행하면 모든 것이 작동합니다.

$ for file in *; do echo "$file"; done
a file2
file1 *

다음은 스크립트의 작동 버전입니다(먼저 테스트해 보세요. 데이터를 볼 수 없습니다).

for file in folder/*
do
     value=$(awk -F, '{print $2}' "$file")
     discard=$(awk -v num1="$value" 'BEGIN { if (num1 > 2.500) print 1; else if (num1 == 0.000) print 0; else print 2 }')

     if [[ $discard -eq 1 || $discard -eq 0 ]]
     then
          printf '"%s" has value="%s"' "$file" "$value" >> path/discard.txt
          rm -- "$file"
     else
          printf '"%s",%s' "$file" "$value" >> path/selected.csv
          rm -- "$file"
     fi
done

답변2

방금 삭제된 요소를 처리하기 위해 TXT 파일 대신 CSV 파일을 사용해 보았습니다. 이제 스크립트가 잘 실행됩니다.

for file in folder/*
do
     value=$(cat "$file" | awk -F, '{print $2}')
     discard=$(awk -v num1="$value" 'BEGIN { if (num1 > 2.500) print 1; else if (num1 == 0.000) print 0; else print 2 }')

     if [[ "$discard" -eq 1 || "$discard" -eq 0 ]]
     then
          echo ""$file" has value="$value"" >> path/discard.csv
          rm -- "$file"
     else
          echo ""$file",$value" >> path/selected.csv
          rm -- "$file"
     fi
done

여러분의 도움과 조언에 감사드립니다!

관련 정보