bash: split output de la commande par colonnes
Je veux faire ceci:
- exécuter une commande
- capturer la sortie
- sélectionnez une ligne
- sélectionnez une colonne de cette ligne
Un exemple, disons que je veux obtenir le nom de la commande à partir d'un $PID
(veuillez noter que ceci est juste un exemple, je ne dis pas que c'est la meilleure façon d'obtenir un nom de commande à partir d'un id de processus - mon vrai problème, c'est avec une autre commande dont le format de sortie que je ne contrôle pas).
Si je lance ps
j'obtiens:
PID TTY TIME CMD
11383 pts/1 00:00:00 bash
11771 pts/1 00:00:00 ps
Maintenant, je ne ps | egrep 11383
et obtenir
11383 pts/1 00:00:00 bash
Prochaine étape: ps | egrep 11383 | cut -d" " -f 4
. Sortie:
<absolutely nothing/>
Le problème est que cut
coupe la sortie par des espaces simples, et que ps
ajoute de certains espaces entre les 2e et 3e colonnes de garder une certaine ressemblance d'une table, cut
choisit une chaîne vide. Bien sûr, je pourrais utiliser cut
pour sélectionner le 7 et non le 4ème champ, mais comment puis-je le sais, spécialement lorsque la sortie est variable et inconnue à l'avance.
- Utiliser awk (et plus de 25 caractères).
Vous devez vous connecter pour publier un commentaire.
Un moyen facile est d'ajouter une passe de
tr
de serrer toutes les répétée séparateurs de champ en sortie:tr
est plus léger queawk
Je pense que le plus simple est d'utiliser awk. Exemple:
ps | awk "\$1==$PID{print\$4}"
ou (mieux)ps | awk -v"PID=$PID" '$1=PID{print$4}'
. Bien sûr, sur Linux, vous pouvez simplement fairexargs -0n1 </proc/$PID/cmdline | head -n1
oureadlink /proc/$PID/exe
, mais de toute façon...;
dans{ print $4; }
nécessaire? Retrait il ne semble avoir aucun effet pour moi sur Linux, juste curieux de savoir à quoi ça sertVeuillez noter que le
tr -s ' '
option ne supprime pas tous seul grand espace. Si votre colonne est aligné à droite (comme avecps
pid)...Puis la coupe va entraîner une ligne vide pour certains de ces champs si c'est la première colonne:
À moins que vous faites-la précéder d'une espace, évidemment
Maintenant, pour ce cas particulier de pid numéros (pas de noms), il y a une fonction appelée
pgrep
:Shell fonctions
Cependant, en général, il est encore possible d'utiliser shell fonctions d'une manière concise, car il y a une chose intéressante à propos de la
read
commande:Le premier paramètre à lire,
a
, sélectionne la première colonne, et si il n'y est plus, tout le reste sera mis enb
. Comme un résultat, vous n'avez jamais besoin de plus de variables que le numéro de votre colonne +1.Donc,
est ensuite sortie de la 3ème colonne. Comme indiqué dans mon commentaire...
Un réseau de lecture sera exécuté dans un environnement qui ne permet pas de passer des variables du script d'appel.
La Solution De Matrice De
Nous avons donc ensuite jusqu'à la fin avec la réponse par @frayser qui est d'utiliser la variable d'environnement IFS qui, par défaut, un espace, pour diviser la chaîne en un tableau. Il ne fonctionne qu'en Bash mais. Tableau de bord et les Cendres ne le supporte pas. J'ai eu un moment difficile de scinder une chaîne en composants dans un Busybox chose. Il est assez facile d'obtenir un seul élément (par exemple, utilisation de awk), puis de répéter que, pour chaque paramètre dont vous avez besoin. Mais alors vous vous retrouvez à plusieurs reprises d'appeler awk sur la même ligne, ou à plusieurs reprises à l'aide d'un bloc de lecture avec de l'écho sur la même ligne. Ce qui n'est pas efficace ou assez. Donc, vous vous retrouvez fractionnement à l'aide de
${name%% *}
et ainsi de suite. Fait vous aspirez pour certains Python compétences, parce que, en fait, les scripts shell n'est pas beaucoup de plaisir si la moitié ou plus des fonctionnalités que vous vous êtes habitués à, sont partis. Mais vous pouvez supposer que, même python ne serait pas installé sur un tel système, et il n'était pas ;-).echo "$a"
etecho "$c"
bien.var=$(....... | { read a b c d; echo $c; })
. Cela ne fonctionne que pour un seul (string), bien qu'en Bash, vous pouvez le diviser en un tableau à l'aidear=($var)
essayer
|&
est nouveau dans Bash 4Similaire à brianegge de awk solution, voici le Perl équivalent:
-a
permet autosplit mode, qui remplit le@F
tableau avec les données de la colonne.Utilisation
-F,
si vos données est délimité par des virgules, plutôt que dans l'espace délimité par des.Champ 3 est imprimé depuis Perl commence à compter à partir de 0 au lieu de 1
De la ligne (par exemple pour la ligne no. 6) se fait avec la tête et la queue, et le mot correct (pas de mot. 4) peut être capturé avec awk:
awk NR=6 {print $4}
serait un peu plus efficaceawk NR==6 {print $4}
*doh*À l'aide de variables de tableau
ou
Au lieu de faire tous ces grep et des trucs, je vous conseille d'utiliser ps capacités de changer le format de sortie.
Vous obtenez la ligne de commande de processus avec le pid spécifié et rien d'autre.
C'est POSIX-conforme et peut être ainsi considéré comme portable.
Votre commande
manque une
tr -s
de serrer les espaces, comme détendez-vous l'explique dans sa réponse.Cependant, peut-être vous voulez utiliser
awk
, car il gère l'ensemble de ces actions en une seule commande:Cette affiche de la 4e colonne dans ces lignes contenant
11383
. Si vous voulez que ce match11383
si elle apparaît au début de la ligne, alors vous pouvez direps | awk '/^11383/{print $4}'
.Bash est
set
va analyser toutes les données de sortie dans les paramètres de position.Par exemple, avec
set $(free -h)
commande,echo $7
affichera "Mem:"set $(sar -r 1 1)
;echo "${23}"
awk
est la meilleure façon d'aller à ce sujet.bash
et pasawk
.