2017-04-13 4 views
1

J'essaie de lire les arguments de la commande ll à partir du fichier. J'ai le fichier args.txt avec le contenu some?. J'ai des fichiers avec les noms some1, some2 et some3 et quelques autres fichiers. quand j'exécute cat args.txt | ll je reçois le même résultat que lorsque j'exécute ll. Est-ce que quelqu'un peut m'expliquer pourquoi est-ce et comment puis-je obtenir le résultat souhaité? Merci d'avance.Lecture d'une liste d'arguments avec un glob à partir d'un fichier

+1

@DPM, BTW, 'll' n'est pas réellement une commande UNIX qui existe. Prêt à l'emploi sur plusieurs systèmes, c'est un * alias *, mais un alias n'est pas une vraie commande - c'est juste une instruction pour le shell de remplacer un préfixe par une chaîne différente avant d'interpréter une commande; les programmes qui ne sont pas shells (et 'xargs' est un tel programme) ne reconnaissent pas les alias et ne peuvent pas les exécuter. –

Répondre

5

Note: Je suppose que ll est un alias pour ls -l ou une variante.
Comme le souligne Charles Duffy, (par défaut) seulement shells interactifs connaître les alias, et les scripts ainsi que des outils tels que xargs ne les connaissent pas.

Qu'est-ce que vous envoyez à travers un pipeline à une commande est reçue via son flux stdin, qui est distinct de d'une commande arguments (options telles que -l et opérandes tels que some?).

Par conséquent, une transformation explicite est nécessaire pour convertir le contenu du fichier args.txt à un argument vous pouvez passer à ls -l:

ls -l $(cat args.txt) # In Bash you can simplify to: ls -l $(< args.txt) 

Notez que la substitution de commande ($(...)) est délibérément unquoted afin de garantir que globalisation (extension de nom de fichier) est appliquée au contenu de args.txt, comme souhaité.

vôtre est un cas rare où cette technique - qui est fragile - est en réalité nécessaire . Pour illustrer la fragilité: Si votre motif de globbing était "some file"?, par exemple (vous auriez besoin des guillemets pour que le motif soit toujours reconnu comme un seul argument), la commande ne fonctionnerait plus, parce que le " les caractères perdent leur fonction syntaxique lorsqu'ils sont le résultat d'une substitution de commande (ou d'une extension de variable).


L'utilitaire standard pour transformer le contenu de l'entrée standard ou un fichier en argument est xargs. Cependant, dans votre cas particulier, il est pas une option, parce que votre fichier contient un glob (modèle de nom de fichier) qui doit être élargit la portée de la coque, mais xargs invoque que les services publics externes, sans impliquer une coquille:

$ xargs ls -l < args.txt # !! Does NOT work as intended here. 
ls: file?: No such file or directory 

nom du fichier file? a été passé littéralement-ls (et aucun fichier nommé réellement file? existe) - pas globbing est arrivé, parce qu'aucun obus a été impliqué.

0

Vous pouvez utiliser xargs pour passer la sortie du chat à la commande (ll dans votre cas):

cat args.txt | xargs ll 

Si votre args.txt contient plusieurs valeurs, séparées par une nouvelle ligne ou dans l'espace, xargs passera chaque valeur séparément, l'exécution de la commande autant de fois, comme entrées dans votre args.txt:

Par exemple, si votre args.txt a ce contenu:

/var/ 
/usr/ 
/usr /var 

Ensuite, les résultats de l'exécution ressemblera à ceci:

$ cat args.txt | xargs ls 
/usr: 
bin etc games include lib lib64 libexec local sbin share src tmp 

/usr/: 
bin etc games include lib lib64 libexec local sbin share src tmp 

/var: 
adm cache crash cvs db empty games gopher kerberos lib local lock log mail nis opt preserve run spool tmp var yp 

/var/: 
adm cache crash cvs db empty games gopher kerberos lib local lock log mail nis opt preserve run spool tmp var yp 
+0

Notez que, par défaut, 'xargs' rassemble autant d'arguments que possible pour une seule ligne, donc il exécute normalement la commande beaucoup moins de fois qu'il n'y a d'entrées dans l'entrée. Il existe des moyens de forcer l'exécution d'une commande par argument. Cela entraîne également une faute de noms de fichiers avec des espaces en eux. –

+1

Si 'll' est un alias, il est peu probable que' xargs ll' fonctionne. –

3

Ce qui suit est un peu exagéré, mais va à peine d'être correcte et cohérente quelle que soit la configuration de la coque et de travailler avec tous les noms possibles (même ceux avec des espaces):

# note f() () instead of f() { }; this runs in a subshell, so its changes to IFS or 
# shopt settings don't modify behavior of the larger shell. 
globfiles() (
    set +f      ## ensure that globbing is enabled 
    shopt -u nullglob failglob ## ensure that non-default options on how to handle failed 
           ## ...glob attempts are both disabled 
    IFS=      ## disable string-splitting 
    while IFS= read -r -d '' filename; do 
    printf '%s\0' $filename ## unquoted use -> expand as glob 
           ## ...expands format string once per argument, hence once per 
           ## ...file found. (No string-splitting due to prior IFS=) 
    done 
) 

... par la suite utilisés comme (si votre fichier d'entrée est délimité par saut de ligne):

tr '\n' '\0' <args.txt | globfiles | xargs -0 ls -l -- 

... ou (si votre fichier d'entrée est NUL délimité - ce qui est idéal, car cela permet les fichiers contenant les nouvelles lignes littérales à référencer):

globfiles <args.0sv | xargs -0 ls -l -- 
+0

Merveilles si cela fonctionnerait avec 'rc'? ... Si oui, Tom Duff serait probablement fier; Je pense qu'il pourrait y avoir une relation lointaine entre vous deux peut-être. –