web-dev-qa-db-fra.com

Préfixe et suffixe des chaînes à chaque ligne de sortie de la commande

J'ai rencontré un problème en essayant d'écrire un script Bash. Lorsque grep sort, il retourne (généralement) plusieurs lignes. Je voudrais préfixer et suffixer une chaîne à chacune de ces lignes de sortie.

Je voudrais également noter que je redirige ls vers grep, comme:

ls | grep
18
SpecialBomb

Avec sed:

ls | grep txt | sed 's/.*/prefix&suffix/'
30
Cyrus

Avec sed:

ls | grep pattern | sed -e 's/^/prefix/' -e 's/$/suffix/'

Mais notez que cela souffre de problèmes avec les noms de fichiers avec des sauts de ligne, et tous les problèmes assortis d'analyse de ls qui est généralement une mauvaise idée.

Avec Perl

Perl -e 'print "prefix".$_."suffix\n" for grep { m/somepattern/} glob "*"'

Remarque - Perl grep peut prendre un modèle - comme la commande grep, mais vous pouvez également faire des choses comme appliquer des tests de fichiers.

Par exemple.

grep {-d} glob "*" #filters directories.
grep { (stat)[9] > time() - 60 } glob "*" #reads file mtime and compares. 

Dans grep l'itérateur par défaut $_ est défini sur la valeur actuelle de l'élément, vous pouvez donc appliquer sed/grep style regex, ou effectuer diverses tâches basées sur $_.

5
Sobrique

Dans ce cas GNU find vous permet de faire toutes ces choses en une seule fois, en éliminant les canaux et l'analyse syntaxique potentiellement gênante de ls:

find . -maxdepth 1 -name '[^.]*' \
  -regextype posix-extended -regex "MYPATTERN" \
  -printf 'SOMEPREFIX %f SOMESUFFIX\n'

(find n'est pas un bon moyen de modifier arbitrairement la sortie d'autres commandes, bien sûr!)

Quelques notes:

  • -maxdepth 1 et -name [^.]* faire en sorte que la correspondance des noms fonctionne de la même façon qu'un ls (ou ls .). Vous pouvez utiliser n'importe quel glob de style Shell, mais notez que "*" correspondra à un "". dans un nom contrairement à bash, donc [^.]* signifie tout ce qui n'a pas un "."
  • MYPATTERN est un ERE POSIX approprié (le type par défaut est Emacs, voir ici ), mais il doit correspondre au nom de fichier complet, donc utilisez quelque chose comme .*thing.* au lieu de simplement thing
  • vous pouvez probablement utilisez simplement l'un des -name/-regex au lieu des deux (par exemple -regex "[^.]. MYPATTERN."
  • -printf prend en charge beaucoup de choses , %n est le nom du fichier ou du répertoire sans fioritures

 (cela peut toutefois dépendre de votre version de find, consultez la section "CONFORMITÉ DES NORMES" de votre page de manuel)

Comme alternative possible sans aucun programme externe requis, bash a compgen qui, entre autres choses, étend les globes, équivalent à un ls sans options:

compgen -P "someprefix>" -S "<somesuffix" -G "pattern"

Cela gère les noms de fichiers avec des espaces, y compris les retours à la ligne. compgen -G "*" devrait fournir la même sortie qu'une simple ls (mais notez que ls * est complètement différent). Vous aurez toujours besoin de grep, et cela peut ou non résoudre le problème, mais cela vaut la peine d'être mentionné.

2
mr.spuratic

sed et find les solutions sont mises à l'épreuve si votre préfixe/suffixe comprend des caractères de clé d'expression régulière ou si vous souhaitez transmettre une variable d'environnement (au lieu d'une valeur immédiate), xargs + echo pourrait être plus approprié ici.

Avec variable d'environnement:

ls | grep p | xargs -I % sh -c "echo $PATH/%"

Avec un inline:

ls | grep p | xargs -I % sh -c "echo `pwd`/%"
0
lashgar