J'ai étudié la ligne de commande et appris que |
(pipeline) est censé rediriger la sortie d'une commande vers l'entrée d'une autre. Alors, pourquoi la commande ls | file
ne fonctionne pas?
file
l’entrée est l’un des noms de fichiers suivants, comme file filename1 filename2
ls
la sortie est une liste de répertoires et de fichiers sur un dossier, donc je pensais ls | file
était censé montrer le type de fichier de chaque fichier d'un dossier.
Quand je l'utilise cependant, la sortie est:
Usage: file [-bcEhikLlNnprsvz0] [--apple] [--mime-encoding] [--mime-type]
[-e testname] [-F separator] [-f namefile] [-m magicfiles] file ...
file -C [-m magicfiles]
file [--help]
Comme il y avait une erreur avec l'utilisation de la file
commande
ls
, cela signifie que vous voulez que tous les fichiers du répertoire en cours soient gérés avec lafile
commande. ... Alors pourquoi ne pas simplement faire:,file *
qui répondra avec une ligne pour chaque fichier, dossier.file *
est le moyen le plus intelligent, je me demandais simplement pourquoi l’utilisation de lals
sortie ne fonctionnait pas. Le doute estls
est généralement une mauvaise idée.Réponses:
Le problème fondamental est que
file
les noms de fichiers doivent être utilisés comme arguments de ligne de commande et non sur stdin. Lorsque vous écrivez,ls | file
le résultat dels
est transmis en tant qu’entréefile
. Pas comme arguments, comme entrée.Quelle est la différence?
Les arguments de ligne de commande sont utilisés lorsque vous écrivez des indicateurs et des noms de fichier après une commande, comme dans
cmd arg1 arg2 arg3
. Dans les scripts shell ces arguments sont disponibles comme variables$1
,$2
,$3
, etc. C Vous les accès viachar **argv
etint argc
argumentsmain()
.L'entrée standard, stdin, est un flux de données. Certains programmes aiment
cat
ouwc
lisent à partir de stdin quand aucun argument de ligne de commande ne leur est attribué. Dans un script shell, vous pouvez utiliserread
une seule ligne d’entrée. En C, vous pouvez utiliserscanf()
ougetchar()
, parmi diverses options.file
ne lit pas normalement à partir de stdin. Il s'attend à ce qu'au moins un nom de fichier soit transmis en tant qu'argument. C'est pourquoi il imprime l'utilisation lorsque vous écrivezls | file
, car vous n'avez pas passé d'argument.Vous pouvez utiliser
xargs
pour convertir stdin en arguments, comme dansls | xargs file
. Cependant, comme le mentionne terdon , l'analyse syntaxiquels
est une mauvaise idée. Le moyen le plus direct de le faire est simplement:la source
file
pour obtenir les noms de fichiers de son entrée, en utilisantls | file -f -
. Encore une mauvaise idée dels
la sortie de cette pipe dansfile
'stdin. Essaye le.file $(ls)
, qui fonctionne également, d’une autre manière encore.Parce que, comme vous le dites, l'entrée de
file
doit être un nom de fichier . La sortie dels
, cependant, n'est que du texte. Le fait qu'il s'agisse d'une liste de noms de fichiers ne change pas le fait qu'il s'agit simplement de texte et non de l'emplacement des fichiers sur le disque dur.Lorsque vous voyez une sortie imprimée à l'écran, vous voyez du texte. Que ce texte soit un poème ou une liste de noms de fichiers ne fait aucune différence pour l'ordinateur. Tout ce qu'il sait, c'est que c'est du texte. C'est pourquoi vous pouvez passer le résultat de
ls
à des programmes qui prennent du texte en entrée (bien que vous ne devriez vraiment pas le faire ):Ainsi, pour utiliser le résultat d'une commande qui répertorie les noms de fichiers sous forme de texte (tel que
ls
oufind
) comme entrée pour une commande prenant des noms de fichiers, vous devez utiliser certaines astuces. L'outil typique pour cela estxargs
:Comme je l’ai déjà dit, vous ne voulez vraiment pas analyser la sortie de
ls
. Quelque chose commefind
est meilleur (lesprint0
impressions d' un\0
lieu d'un newilne après chaque nom de fichier et-0
de laxargs
laisse traiter avec une telle entrée, ce qui est une astuce pour faire vos commandes travail avec les noms de fichiers contenant des sauts de ligne):Ce qui a aussi sa propre façon de faire cela, sans avoir besoin
xargs
de rien du tout:Enfin, vous pouvez également utiliser une boucle de shell. Cependant, notez que dans la plupart des cas,
xargs
sera beaucoup plus rapide et plus efficace. Par exemple:la source
file
ne semble pas vraiment lire stdin à moins donné un explicite-
espace réservé: comparerfile foo
,echo foo | file
etecho foo | file -
; en fait c'est probablement la raison du message d'utilisation dans le cas des PO (c'est-à-dire que ce n'est pas vraiment parce que le résultatls
est "text simplement", mais plutôt parce que la liste d'arguments àfile
est vide)echo foo | file -
cela ne fonctionne pas réellementfile
sur le fichierfoo
mais sur le flux stdin.cat
celui-là, sauf stdin sans-
sauf quand on me donne des arguments de fichier aussi, je pense?Il ne "redirige" pas la sortie, mais prend la sortie d'un programme et l'utilise comme entrée, alors que le fichier ne prend pas les entrées mais noms de fichiers en tant qu'arguments , qui sont ensuite testés. Les redirections ne transmettent pas ces noms de fichiers sous forme d'arguments, pas plus que la tuyauterie , ce que vous faites plus tard.
Ce que vous pouvez faire, c'est lire les noms de fichiers d'un fichier avec l'
--files-from
option si vous avez un fichier qui répertorie tous les fichiers que vous souhaitez tester, sinon, passez simplement les chemins d'accès à vos fichiers comme arguments.la source
La réponse acceptée explique pourquoi la commande de canal ne fonctionne pas immédiatement et
file *
offre une solution simple et directe.J'aimerais suggérer une autre solution qui pourrait être utile à un moment donné. L'astuce consiste à utiliser le
(`)
caractère backtick . Le backtick est expliqué en détail ici . En bref, il prend la sortie de la commande incluse dans les backticks et la remplace par une chaîne dans la commande restante.Donc,
find `ls`
prendra le résultat de lals
commande et le substituera comme argument de lafind
commande. C'est plus long et plus compliqué que la solution acceptée, mais des variantes peuvent être utiles dans d'autres situations.la source
command
(impossible de trouver le code de barre oblique inverse sur mon téléphone) pour développer le résultat d'une commande dans le bash et l'utiliser comme paramètre pour d'autres commandes. Vraiment utile, même si l’utiliser dans ce cas (avec ls ) résulterait quand même en quelques problèmes à cause des caractères spéciaux sur certains noms de fichiers.La sortie de
ls
via un canal est un bloc solide de données avec 0x0a séparant chaque ligne - c’est-à-dire un caractère de saut de ligne - etfile
obtient en tant que paramètre unique, dans lequel plusieurs caractères doivent fonctionner sur un à la fois.En règle générale, ne jamais utiliser
ls
pour générer une source de données pour d'autres commandes - un jour, cela va canaliser .. dansrm
et vous aurez alors des problèmes!Mieux vaut utiliser une boucle, telle que celle
for i in *; do file "$i" ; done
qui produira le résultat souhaité, de manière prévisible. Les citations sont là en cas de noms de fichiers avec des espaces.la source
file *
;-)ls
est une très, très mauvaise idée . Pas seulement parce que vous pourriez le transmettre à quelque chose de dangereux, commerm
, plus important encore, parce qu'il casse tout nom de fichier non standard.rm
noms de fichiers sont pris de l'entrée standard? Je crois que non. De même, en règle générale, l’ls
un des principaux exemples de sources de données pour l’utilisation des pipelines Unix depuis le début d’Unix. C'est pourquoi il utilise par défaut un simple nom de fichier par ligne sans attributs ni ornements lorsque sa sortie est un tube, contrairement à son formatage par défaut habituel lorsque la sortie est le terminal.Si vous souhaitez utiliser un tube pour alimenter,
file
utilisez l'option-f
qui est normalement suivie d'un nom de fichier, mais vous pouvez également utiliser un seul trait-
d' union pour lire à partir de stdin.L’astuce avec le trait d’union utilise
-
beaucoup des utilitaires de ligne de commande standard (bien qu’il soit--
parfois le cas), il est donc toujours intéressant d'essayer.L'outil
xarg
est beaucoup plus puissant et n'est généralement nécessaire que si la liste d'arguments est trop longue (voir cet article pour plus de détails).la source
--
? Je n'ai jamais vu ça.--
est typiquement l'indicateur "fin des drapeaux".Cela fonctionne utiliser la commande comme ci-dessous
Cela fonctionnera mieux pour moi
la source
Cela devrait également fonctionner:
comme discuté ici: https://unix.stackexchange.com/questions/5778/whats-the-difference-between-stuff-and-stuff
la source
$()
méthode est la même que la méthode de backtick