rm fails to delete files by wildcard from a script, but works from a shell prompt

前端 未结 6 600
广开言路
广开言路 2021-01-30 19:51

I\'ve run into a really silly problem with a Linux shell script. I want to delete all files with the extension \".bz2\" in a directory. In the script I call

rm \         


        
相关标签:
6条回答
  • 2021-01-30 20:25

    The quotes are causing the string to be interpreted as a string literal, try removing them.

    0 讨论(0)
  • 2021-01-30 20:25

    Why not just rm -rf */*.bz2? Works for me on OSX.

    0 讨论(0)
  • 2021-01-30 20:34

    TL;DR

    Quote only the variable, not the whole expected path with the wildcard

    rm "$archivedir"/*.bz2
    

    Explanation

    • In Unix, programs generally do not interpret wildcards themselves. The shell interprets unquoted wildcards, and replaces each wildcard argument with a list of matching file names. if $archivedir might contain spaces, then rm $archivedir/*.bz2 might not do what you

    • You can disable this process by quoting the wildcard character, using double or single quotes, or a backslash before it. However, that's not what you want here - you do want the wildcard expanded to the list of files that it matches.

    • Be careful about writing rm $archivedir/*.bz2 (without quotes). The word splitting (i.e., breaking the command line up into arguments) happens after $archivedir is substituted. So if $archivedir contains spaces, then you'll get extra arguments that you weren't intending. Say archivedir is /var/archives/monthly/April to June. Then you'll get the equivalent of writing rm /var/archives/monthly/April to June/*.bz2, which tries to delete the files "/var/archives/monthly/April", "to", and all files matching "June/*.bz2", which isn't what you want.

    The correct solution is to write:

    rm "$archivedir"/*.bz2
    0 讨论(0)
  • Just to expand on this a bit, bash has fairly complicated rules for dealing with metacharacters in quotes. In general

    • almost nothing is interpreted in single-quotes:

       echo '$foo/*.c'                  => $foo/*.c
       echo '\\*'                       => \\*
      
    • shell substitution is done inside double quotes, but file metacharacters aren't expanded:

       FOO=hello; echo "$foo/*.c"       => hello/*.c
      
    • everything inside backquotes is passed to the subshell which interprets them. A shell variable that is not exported doesn't get defined in the subshell. So, the first command echoes blank, but the second and third echo "bye":

      BAR=bye echo `echo $BAR`
      BAR=bye; echo `echo $BAR`
      export BAR=bye; echo `echo $BAR`
      

    (And getting this to print the way you want it in SO takes several tries is apparently impossible...)

    0 讨论(0)
  • 2021-01-30 20:38

    I've seen similar errors when calling a shell script like ./shell_script.sh from another shell script. This can be fixed by invoking it as sh shell_script.sh

    0 讨论(0)
  • 2021-01-30 20:43

    Your original line

    rm "$archivedir/*.bz2"
    

    Can be re-written as

    rm "$archivedir"/*.bz2
    

    to achieve the same effect. The wildcard expansion is not taking place properly in your existing setup. By shifting the double-quote to the "front" of the file path (which is legitimate) you avoid this.

    0 讨论(0)
提交回复
热议问题