`ls`는 bash 스크립트 내부와 외부에서 다르게 동작합니다.

`ls`는 bash 스크립트 내부와 외부에서 다르게 동작합니다.

저는 시놀로지 NAS를 사용하고 있습니다. 삭제할 파일 목록이 있고 파일 이름에 전체 경로가 나열되어 있습니다 Myfiles.txt. 파일에는 약 3000줄이 있으며 다음과 같습니다.

"/volume2/NBU/Downloads/AA_To be seen/Life.Itself.2018.1080p.WEB-DL.DD5.1.H264-FGT/RARBG.txt"
"/volume2/nbU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E16.High.Stakes.Hip.Hop.WEBRip.x264-ION10.mp4"
"/volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E14.Time.to.Face.the.Music.WEBRip.x264-ION10.mp4"

다음 스크립트를 사용하고 있습니다( ls나중에 교체되도록 테스트됨 rm -f).

#!/bin/bash
while IFS="" read -r p;
do
  ls "$p"
done < "Myfiles.txt"

불행하게도 스크립트를 실행하면 루프마다 다음 메시지와 함께 오류가 발생합니다.

ls: cannot access "/volume2/NBU/Downloads/AA_To be seen/Life.Itself.2018.1080p.WEB-DL.DD5.1.H264-FGT/RARBG.txt": No such file or directory
ls: cannot access "/volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E16.High.Stakes.Hip.Hop.WEBRip.x264-ION10.mp4": No such file or directory
ls: cannot access "/volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E14.Time.to.Face.the.Music.WEBRip.x264-ION10.mp4": No such file or directory

그러나 명령줄에서 직접 해당 줄을 실행하면 작동합니다. 예를 들어:

ll "/volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E14.Time.to.Face.the.Music.WEBRip.x264-ION10.mp4"

출력은 다음과 같습니다.

-rwxrwxrwx+ 1 Pansysadmin users 275337817 Dec 15  2018 /volume2/NBU/Downloads/AA_To be seen/Find.Me.in.Paris.S01.WEBRip.x264-ION10/Find.Me.in.Paris.S01E14.Time.to.Face.the.Music.WEBRip.x264-ION10.mp4

실행 스크립트를 사용해도 sudo동일한 오류가 발생합니다.

내가 무엇을 간과하고 있습니까?

답변1

따옴표는 파일 이름의 일부가 아닙니다. 과 같은 파일을 삭제하려고 하는데 "file.txt"파일 이름이 실제로 입니다 file.txt.

touch "file.txt"    # shell uses quotes; name is simply file.txt
ls "file.txt"       # quotes used by shell; success
ls file.txt         # no quotes; success
ls '"file.txt"'     # outer quotes used by shell to treat word-with-quotes as literal; failure

파일 이름이 올바르도록(즉, 파일 이름 주위에 큰따옴표가 없도록) 파일 이름을 수정하거나 루프를 수정하여 데이터의 잘못된 부분을 제거하십시오.

방금 시도해 봤다는 귀하의 의견을 보았습니다 sudo. sudo왜 필요한지 먼저 이해하지 않은 채 그것에 의존하지 마십시오. (여기에서는 그럴 필요가 없습니다.) 그렇지 않으면 어느 날 시스템이 제공하려고 했던 보호 기능을 실수로 우회하여 시스템이 손상될 수도 있습니다.

답변2

크게 하다엠마 루오의 답변,

  • 셸에 명령을 실행하면 명령줄에서 많은 처리와 해석이 수행됩니다. 예를 들어:

    • 당신이 입력하면
      ls foo bar
      
      쉘은 및 의 ls두 가지 인수로 실행됩니다 . 하지만 입력하면 foobar
      ls "foo bar"
      
      쉘은 ls하나의 인수로 실행됩니다: foo bar.
    • 당신이 입력하면
      rm north*
      
      쉘은 , 등과 rm같은 많은 매개변수로 실행됩니다 north1. 하지만 입력하면 north42northwest
      rm "north*"
      
      쉘은 rm하나의 인수로 실행됩니다: north*.
    • 당신이 입력하면
      echo Math tells us that 5 > 4.
      
      쉘은 이름이 지정된 파일을 생성하고 4. 해당 파일에 내용을 씁니다. Math tells us that 5등.
  • read명령이 입력을 읽을 때 처리를 수행하지 않습니다. 특히, 입력 줄에 , 및 같은 read특수 문자가 포함되어 있으면 해당 문자만 변수에 입력됩니다 . 공백과 탭은 일반적으로 여전히 특별한 의미를 가지고 있지만 를 사용하여 억제할 수 있습니다 . 백슬래시( )는 일반적으로 여전히 특별한 의미를 갖지만 성공을 사용하여 억제할 수 있습니다 . 시작과 끝 으로 설정된 파일 이름에도 마찬가지입니다 .*>"pIFS=\read -rp"

  • 변수 값을 확장하는 것은 쉘이 수행하는 마지막 작업 중 하나입니다. 예를 들어 다음과 같은 작업을 수행할 수 있습니다.

    statement="Math tells us that 5 > 4."
    echo $statement
    

    쉘은 변수 내용의 문자를 Math tells us that 5 > 4.확인하지 않기 때문에 (터미널에) 씁니다  .statement>

    참고: 위의 내용은 나쁜 예입니다. 일반적으로 말하면 다음과 같이 말해야 합니다.

    echo "$statement"
    

    즉, 따옴표가 있습니다.

  • 그래서 당신이 말할 때

    ls "$p"
    

    쉘은 ls따옴표 문자가 포함된 인수로 실행됩니다. 이는 본질적으로 동일합니다.

    ls '"/volume2/NBU/Downloads/AA_To be seen/Life.Itself … H264-FGT/RARBG.txt"'
    

    (따옴표 안의 따옴표에 주목하세요) 그리고 실제 파일 이름에는 따옴표가 포함되어 있지 않습니다.

관련 정보