Utiliser l'espace comme délimiteur avec la commande cut

328

Je veux utiliser l'espace comme délimiteur avec la cutcommande.

Quelle syntaxe puis-je utiliser pour cela?

Jaelebi
la source
42
faux, la page de manuel de cut n'explique pas cela et n'est, en général, pas informative
UncleZeiv
2
En outre, "info cut" n'est pas une amélioration dans ce cas.
Space Man à Cardiff le
3
@ mklement0 si je me souviens bien, je répondais à un commentaire qui a depuis été supprimé, qui rejetait cette question comme étant répondue dans la page de manuel, qui était à mon avis "fausse", malgré qu'il y ait une bonne raison pour cela ou pas - maintenant, même si je concède qu'il pourrait y avoir une bonne raison à ce manque d'informations, je pense toujours que la documentation sans exemples d'utilisation courante est souvent au moins irritante, quand elle n'est pas carrément inutile
UncleZeiv
3
@UncleZeiv J'ai compris; Merci de clarifier; étant donné l'intérêt pour cette question, il est juste de supposer que la manpage n'est pas suffisante. Jetons un coup d'œil: " -d delimUtiliser delimcomme caractère de délimitation de champ au lieu du caractère de tabulation." (BSD cut, mais la version GNU et la spécification POSIX indiquent à peu près la même chose). L'utilisation d'un shell pour invoquer cut- le cas typique - vous oblige donc à savoir comment passer généralement un espace comme argument en utilisant la syntaxe du shell , ce qui n'est sans doute pas le cuttravail de la page de manuel. Cependant, les exemples réels aident toujours et la page de manuel GNU en manque.
mklement0
4
bien que la réponse sélectionnée soit techniquement correcte, envisagez de sélectionner la réponse la plus récente et la plus complète par @ mklement0 comme réponse canonique afin qu'elle filtre vers le haut.
David LeBauer

Réponses:

367
cut -d ' ' -f 2

Où 2 est le numéro de champ du champ délimité par des espaces que vous souhaitez.

RichieHindle
la source
2
pouvez-vous dire à cut d'utiliser n'importe quel nombre d'un certain caractère comme délimiteur, comme dans RegEx? par exemple n'importe quel nombre d'espaces, par exemple \ s +
amphibient
3
@foampile Non, je ne pense pas que vous puissiez.
Jonathan Hartley
6
Vous ne pouvez pas utiliser d'expressions rationnelles avec cut, mais vous pouvez avec cutsqui essaie de "corriger" toutes les cutlimitations: github.com/arielf/cuts
arielf
pouvez-vous obtenir chaque troisième champ délimité par l'espace? comme cut -d ' ' -f 3,6,9,12,15,18sans avoir à spécifier chaque numéro?
Monocito
169

Généralement, si vous utilisez l'espace comme délimiteur, vous souhaitez traiter plusieurs espaces comme un seul, car vous analysez la sortie d'une commande alignant certaines colonnes avec des espaces. (et la recherche google qui me mène ici)

Dans ce cas, une seule cutcommande n'est pas suffisante et vous devez utiliser:

tr -s ' ' | cut -d ' ' -f 2

Ou

awk '{print $2}'
BeniBela
la source
2
Merci pour l'utilisation de l'exemple awk, juste ce dont j'avais besoin.
spazm
44

Pour compléter les réponses existantes et utiles; bout du chapeau au support QZ pour m'avoir encouragé à poster une réponse séparée:

Deux mécanismes distincts entrent en jeu ici:

  • (a) si cut lui-même nécessite le délimiteur (espace, dans ce cas) passé à l' -doption pour être un argument séparé ou s'il est acceptable de l'ajouter directement à -d.

  • (b) comment le shell analyse généralement les arguments avant de les passer à la commande invoquée.

(a) est répondu par une citation des lignes directrices POSIX pour les services publics (c'est moi qui souligne)

Si le SYNOPSIS d'un utilitaire standard montre une option avec un argument d'option obligatoire, [...] une application conforme doit utiliser des arguments séparés pour cette option et son argument d'option . Cependant , une implémentation conforme doit également permettre aux applications de spécifier l'option et l'option-argument dans la même chaîne d'arguments sans caractères intermédiaires .

En d'autres termes: dans ce cas, comme -dl'argument option de 'est obligatoire , vous pouvez choisir de spécifier le délimiteur comme :

  • (s) Soit: un argument distinct
  • (d) OU: en tant que valeur directement attachée à-d .

Une fois que vous avez choisi (s) ou (d), c'est l' analyse syntaxique littérale du shell - (b) - qui compte:

  • Avec l' approche (s) , toutes les formes suivantes sont équivalentes:

    • -d ' '
    • -d " "
    • -d \<space> # <space> used to represent an actual space for technical reasons
  • Avec l'approche (d) , toutes les formes suivantes sont ÉQUIVALENTES:

    • -d' '
    • -d" "
    • "-d "
    • '-d '
    • d\<space>

L'équivalence s'explique par le shell traitement littéral de chaîne :

Toutes les solutions ci-dessus donnent la même chaîne exacte (dans chaque groupe) au moment où cutelles les voient :

  • (s) : cutvoit -d, comme son propre argument, suivi d'un argument séparé qui contient un caractère espace - sans guillemets ni \préfixe !.

  • (d) : cutvoit -d plus un caractère d'espace - sans guillemets ni \préfixe! - dans le cadre du même argument.

La raison pour laquelle les formulaires dans les groupes respectifs sont finalement identiques est double, en fonction de la façon dont le shell analyse les littéraux de chaîne :

  • Le shell permet de spécifier le littéral tel quel via un mécanisme appelé citation , qui peut prendre plusieurs formes :
    • chaînes entre guillemets simples : le contenu à l'intérieur '...'est pris littéralement et forme un seul argument
    • chaînes entre guillemets doubles : le contenu à l'intérieur "..."forme également un seul argument, mais est soumis à une interpolation (développe les références de variables telles que $var, les substitutions de commande ( $(...)ou `...`), ou les extensions arithmétiques ( $(( ... ))).
    • \-quotation de caractères individuels : un \précédant un seul caractère fait que ce caractère est interprété comme un littéral.
  • La citation est complétée par la suppression des guillemets , ce qui signifie qu'une fois que le shell a analysé une ligne de commande, il supprime les caractères de citation des arguments (entourant '...'ou "..."ou des \instances) - ainsi, la commande invoquée ne voit jamais les caractères de citation .
mklement0
la source
36

Vous pouvez également dire:

cut -d\  -f 2

Notez qu'il y a deux espaces après la barre oblique inverse.

Chas. Owens
la source
30
La personne qui sait que «\» échappe au personnage suivant serait très attentive à noter ce qui a suivi. L'utilisation de '\' pour échapper des caractères spatiaux comme celui-ci est un idiome très courant.
Jonathan Hartley
3
@Jonathan Hartley généralement la plupart des codes sont illisibles en effet :)
Luca Borrione
1
Du point de vue linux / unix, \ c'était ma première tentative et cela a fonctionné. Je suis d'accord que c'est moins évident par rapport à ' ', mais je suis sûr que beaucoup sont heureux de le lire ici pour rassurer sur le comportement. Pour une meilleure compréhension, veuillez voir le commentaire de @ mklement0 ci-dessous.
tresf
@JonathanHartley correction: "la personne égoïste qui sait que '\' échappe au personnage suivant et suppose que tout le monde le sait aussi". Pour les projets personnels, cela ne s'applique pas, mais en équipe, cette hypothèse est très dangereuse (et potentiellement coûteuse).
Eduard Nicodei
1
@EduardNicodei Oh je suis d'accord. Nous parlions de lecteurs du code ("qui remarque ...?"), Pas d'auteurs. Mais aussi, dans certaines équipes, c'est bien de supposer un certain niveau de compétence. Dépend de l'environnement.
Jonathan Hartley
5

Je viens de découvrir que vous pouvez également utiliser "-d ":

cut "-d "

Tester

$ cat a
hello how are you
I am fine
$ cut "-d " -f2 a
how
am
fedorqui 'SO arrête de nuire'
la source
1
En effet - ou '-d '.
mklement0
3
Notez que de cut« de la perspective tous les éléments suivants sont identiques: "-d ", '-d ', -d" ", -d' 'et -d\<space>: toutes les formes directement append l'argument de l' option (un espace) à l'option ( -d) et le résultat dans la même chaîne exacte au moment où cutles voit: un argument contenant d suivi d'un espace, après que le shell a effectué la suppression du devis
mklement0
1
La réponse de @ mklement0 devrait être la réponse. C'est le plus complet de cette page (même s'il s'agit d'un commentaire).
tresf
@QZSupport: J'apprécie le sentiment et l'encouragement - cela m'a inspiré pour poster ma propre réponse avec des informations de base supplémentaires.
mklement0
1
Découverte fascinante lol!
Harry
4

Vous ne pouvez pas le faire facilement avec cut si les données ont par exemple plusieurs espaces. J'ai trouvé utile de normaliser l'entrée pour un traitement plus facile. Une astuce consiste à utiliser sed pour la normalisation comme ci-dessous.

echo -e "foor\t \t bar" | sed 's:\s\+:\t:g' | cut -f2  #bar
Anssi
la source
3

scut , un utilitaire de coupe (plus intelligent mais plus lent que j'ai créé) qui peut utiliser n'importe quel regex perl comme un jeton de rupture. La rupture sur les espaces est la valeur par défaut, mais vous pouvez également casser sur les expressions régulières multi-caractères, les expressions régulières alternatives, etc.

scut -f='6 2 8 7' < input.file  > output.file

donc la commande ci-dessus casserait les colonnes sur les espaces et extrairait les colonnes (basées sur 0) 6 2 8 7 dans cet ordre.

Harry Mangalam
la source
0

J'ai une réponse (j'avoue une réponse quelque peu confuse) qui implique seddes expressions régulières et des groupes de capture:

  • \S* - premier mot
  • \s* - délimiteur
  • (\S*) - deuxième mot - capturé
  • .* - reste de la ligne

Comme sedexpression, le groupe de capture doit être échappé, c'est \(-à- dire et\) .

Le \1retourne une copie du groupe capturé, c'est-à-dire le deuxième mot.

$ echo "alpha beta gamma delta" | sed 's/\S*\s*\(\S*\).*/\1/'
beta

Lorsque vous regardez cette réponse, elle est quelque peu déroutante et, vous pensez peut-être, pourquoi s'embêter? Eh bien, j'espère que certains vont devenir "Aha!" et utilisera ce modèle pour résoudre certains problèmes complexes d'extraction de texte avec une seule sedexpression.

Stephen Quan
la source