`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

ファイル名が正しく(つまり、ファイル名の周りに二重引用符がないように)、ファイル名を変更するか、ループを変更してデータの誤った部分を削除してください。

試してみたばかりのコメントを見ましたsudosudoなぜ必要なのかまず理解しないで、それに頼らないでください。 (ここでは必要ありません。)そうしないと、ある日システムが提供しようとした保護機能を誤ってバイパスし、システムが損傷する可能性があります。

答え2

大きくするエマ・ルーオの答え

  • シェルでコマンドを実行すると、コマンドラインで多くの処理と解釈が実行されます。たとえば、

    • 入力したら
      ls foo bar
      
      シェルはとのls2つの引数で実行されます。しかし、入力すると foobar
      ls "foo bar"
      
      シェルはls1つの引数で実行されますfoo bar
    • 入力したら
      rm north*
      
      シェルは、などrmのような多くのパラメータで実行されますnorth1。しかし、入力すると north42northwest
      rm "north*"
      
      シェルはrm1つの引数で実行されますnorth*
    • 入力したら
      echo Math tells us that 5 > 4.
      
      シェルは名前付きファイルを生成し、4. そのファイルに内容を書き込みます。Math tells us that 5など。
  • readコマンドが入力を読み取るときは処理しません。特に、入力行に、などのread特殊文字が含まれている場合、その文字のみが変数に入力されます。スペースとタブは通常、まだ特別な意味を持っていますが、を使用して抑制することができます。バックスラッシュ()は通常まだ特別な意味を持ちますが、成功を使用して抑制することができます。開始と終了に設定されたファイル名にも同様です。*>"pIFS=\read -rp"

  • 変数値の拡張は、シェルが実行する最後の操作の1つです。たとえば、次の操作を実行できます。

    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"'
    

    (引用符内の引用符に注意してください)、実際のファイル名には引用符は含まれていません。

関連情報