Pourquoi est-ce que "sort <" $ f1 "" est préféré à "sort -" $ f1 "`, et pourquoi est-ce préféré à `sort" $ f1 "`?

29

Depuis /unix//a/458074/674

N'oubliez pas d'utiliser -- lors du passage d'arguments arbitraires aux commandes (ou utilisez des redirections si possible). Alors sort -- "$f1"ou mieux sort < "$f1"au lieu de sort "$f1".

Pourquoi est-il préférable d'utiliser --et de rediriger?

Pourquoi est sort < "$f1"préféré à sort -- "$f1"?

Pourquoi est sort -- "$f1"préféré à sort "$f1"?

Merci.

Tim
la source

Réponses:

55
sort "$f1"

échoue pour les valeurs $f1commençant par -ou ici pour le cas de sortcertaines commençant par +(peut avoir de graves conséquences pour un fichier appelé -o/etc/passwdpar exemple).

sort -- "$f1"

(où -- signale la fin des options) résout la plupart de ces problèmes mais échoue toujours pour le fichier appelé -(qui sortinterprète comme signifiant son stdin à la place).

sort < "$f1"

N'a pas ces problèmes.

Ici, c'est le shell qui ouvre le fichier. Cela signifie également que si le fichier ne peut pas être ouvert, vous obtiendrez également un message d'erreur potentiellement plus utile (par exemple, la plupart des shells indiqueront le numéro de ligne dans le script), et le message d'erreur sera cohérent si vous utilisez des redirections autant que possible pour ouvrir des fichiers.

Et en

sort < "$f1" > out

(contrairement à sort -- "$f1" > out), s'il "$f1"ne peut pas être ouvert, outne sera pas créé / tronqué et sortne sera même pas exécuté.

Pour effacer une certaine confusion possible (après les commentaires ci-dessous), cela n'empêche pas la commande d' mmap()ingérer le fichier ou d' y pénétrer lseek()(ce sortn'est pas le cas non plus) à condition que le fichier lui-même soit recherché. La seule différence est que le fichier est ouvert plus tôt et sur le descripteur de fichier 0 par le shell par opposition à plus tard par la commande éventuellement sur un descripteur de fichier différent. La commande peut toujours rechercher / mmap qui fd 0 à sa guise. Cela ne doit pas être confondu avec cat file | cmdcmdle stdin de cette fois est un tuyau qui ne peut pas être mappé / recherché.

Stéphane Chazelas
la source
4
N'oubliez pas que l'utilisation d'une redirection oblige sortà lire les données séquentiellement et vous ne pouvez pas mmaple fichier. Bien que cela sortpuisse ne pas avoir beaucoup de problèmes, considérez les performances de less <fileet less file. Dans le premier cas, il lessdoit conserver tout le contenu du fichier dans la mémoire, dans le second cas, il est autorisé à lire uniquement les parties qu'il souhaite. Imaginez maintenant qu'il files'agit d'un fichier journal de 100 Go ...
styrofoam fly
7
@styrofoamfly: C'est correct qui less <filegarde tout le fichier en mémoire, mais ce n'est pas forcé, c'est un défaut de moins. Seul cat file | lessest obligé de le faire. Vérifiez less /dev/fd/0 <f, qui ne conserve pas le fichier en mémoire, même s'il le reçoit sur stdin. C'est une idée fausse très répandue que stdin sous Unix est imprenable. En fait, il peut être recherché, selon le type de fichier.
pts
@styrofoamfly Voulez-vous dire que read()lire les données séquentiellement à partir d'un fichier, tout en mmap()lisant le fichier entier en mémoire à la fois?
Tim
1
@JohnBollinger Non. Cela remonte au moins aussi loin que getopt de SysIII en 1980 avant le démarrage du projet GNU et doit être pris en charge pour la plupart des utilitaires standard, y compris sortpar POSIX. Mais c'est vrai que ce n'est pas toujours supporté.
Stéphane Chazelas
2
Mes excuses, @ StéphaneChazelas, vous avez raison sur l'origine de la convention, et je préciserai en outre que la spécification POSIX pour la getopt()fonction C reconnaît cette signification de l'argument --. Mais le point principal est celui que vous acceptez: la gestion des arguments est le domaine des programmes individuels, et tous ne les traitent pas --spécialement.
John Bollinger
17

Le problème est le nom des fichiers commençant par un tiret. sort "$f1"ne fonctionne pas si la valeur de f1commence par -car la commande interprétera la valeur comme une option. Cela entraîne généralement une erreur, mais cela peut même entraîner une faille de sécurité . Avec sort -- "$f1", l'argument double tiret --signifie «aucune option au-delà de ce point», donc la valeur de f1ne sera pas interprétée comme une option. Mais il y a encore un cas de bord: si la valeur de f1est un tiret et rien d'autre, alors ce n'est pas une option, c'est l'argument -, qui signifie «entrée standard» (car l'argument est un fichier d'entrée; pour un fichier de sortie cela signifierait «sortie standard»).

L'utilisation de la redirection évite tous ces pièges.

Cela s'applique à la plupart des commandes, pas seulement sort.

Gilles 'SO- arrête d'être méchant'
la source
Voulez-vous dire que sort < "$f1"cela fonctionnerait si la valeur était égale à -? Ce n'est dans aucun shell que j'ai essayé.
grawity
@grawity, comparer seq 10 > -; sort -avec seq 10 > -; sort < -.
Stéphane Chazelas