web-dev-qa-db-fra.com

Existe-t-il des inconvénients à utiliser rm $ (ls) pour supprimer des fichiers?

Je me demandais si utiliser rm $(ls) pour supprimer des fichiers (ou rm -r $(ls) pour supprimer également des répertoires) était sûr? Parce que dans tous les sites Web, les gens donnent d'autres moyens de le faire, même si cette commande semble beaucoup plus facile que d'autres.

13
posixKing

Qu'est-ce que cela est destiné à faire?

  • ls répertorie les fichiers du répertoire en cours
  • $(ls) remplace la sortie de ls place celui-ci en tant qu'argument pour rm
  • Essentiellement rm $(ls) est destiné à supprimer tous les fichiers du répertoire en cours

Qu'est-ce qui ne va pas avec cette image ?

ls ne peut pas gérer correctement les caractères spéciaux dans le nom du fichier. Les utilisateurs Unix en général conseillé d'utiliser différentes approches . J'ai également montré cela dans un question connexe sur le comptage des noms de fichiers . Par exemple:

$ touch file$'\n'name                                                                                                    
$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ 

De plus, comme mentionné à juste titre dans la réponse de Denis, un nom de fichier avec des tirets, pourrait être interprété comme un argument de rm après la substitution, ce qui irait à l'encontre du but de la suppression du nom de fichier.

Ce qui fonctionne

Vous voulez supprimer des fichiers dans le répertoire actuel. Donc utilisez glob rm *:

$ ls                                                                                                                     
file?name
$ rm $(ls)
rm: cannot remove 'file': No such file or directory
rm: cannot remove 'name': No such file or directory
$ rm *
$ ls
$ 

Vous pouvez utiliser la commande find. Cet outil est fréquemment recommandé pour plus que le seul répertoire en cours - il peut parcourir de manière récursive toute une arborescence de répertoires et agir sur des fichiers via -exec . . .{} \;

$ touch "file name"                                
$ find . -maxdepth 1 -mindepth 1                                                                                         
./file name
$ find . -maxdepth 1 -mindepth 1 -exec rm {} \;                                                                          
$ ls
$ 

Python n’ayant pas de problème avec les caractères spéciaux dans les noms de fichiers, nous pourrions aussi l’utiliser (notez que celui-ci est réservé aux fichiers, vous devrez utiliser os.rmdir() et os.path.isdir() si vous voulez utiliser sur les annuaires):

python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

En fait, la commande ci-dessus pourrait être transformée en fonction ou en alias dans ~/.bashrc par souci de concision. Par exemple,

rm_stuff()
{
    # Clears all files in the current working directory
    python -c 'import os; [ os.remove(i) for i in os.listdir(".") if os.path.isfile(i) ]'

}

La version Perl de ce serait

Perl -e 'use Cwd;my $d=cwd();opendir(DIR,$d); while ( my $f = readdir(DIR)){ unlink $f;}; closedir(DIR)'
7

Non, ce n'est pas sûr et l'alternative communément utilisée rm * n'est pas beaucoup plus sûre.

Il y a de nombreux problèmes avec rm $(ls). Comme d'autres l'ont déjà mentionné dans leurs réponses, le résultat de ls sera divisé en caractères présents dans le séparateur de champs interne .

Dans le meilleur des cas, cela ne fonctionne tout simplement pas. Dans le pire des cas, vous vouliez supprimer uniquement les fichiers (mais pas les répertoires) - ou supprimer sélectivement certains fichiers avec -i - mais il existe un fichier nommé c -rf dans le répertoire actuel. Voyons ce qui se passe.

$ mkdir a
$ touch b
$ touch 'c -rf'
$ rm -i $(ls)
$ ls
c -rf

La commande rm -i $(ls) était supposée ne supprimer que les fichiers et demander avant de les supprimer, mais la commande qui a finalement été exécutée a été lue.

rm -i a b c -rf

alors il a fait autre chose entièrement.

Notez que rm * n'est que légèrement meilleur. Avec la structure de répertoires comme auparavant, il se comportera comme prévu ici, mais si vous avez un fichier appelé -rf, vous n’avez toujours pas de chance.

$ mkdir a
$ touch b
$ touch ./-rf
$ rm -i *
$ ls
-rf

Il existe plusieurs meilleures alternatives. Les plus faciles impliquent seulement rm et globbing.

  • La commande

    rm -- *
    

    fonctionnera exactement comme prévu, où -- indique que tout ce qui suit ne doit pas être interprété comme une option.

    Cela fait partie des directives de syntaxe de l'utilitaire POSIX depuis plus de deux décennies. C'est répandu, mais vous ne devriez pas vous attendre à ce qu'il soit présent partout.

  • La commande

    rm ./*
    

    rend le glob se développer différemment et ne nécessite donc aucun support de l'utilitaire appelé.

    Pour mon exemple ci-dessus, vous pouvez voir la commande qui sera finalement exécutée en ajoutant un préfixe echo .

    $ echo rm ./*
    rm ./a ./b ./-rf
    

    Le ./ initial permet d'empêcher rm de traiter accidentellement les noms de fichiers comme des options.

27
Dennis