Je veux faire ça:
- exécuter une commande
- capturer la sortie
- sélectionnez une ligne
- sélectionnez une colonne de cette ligne
À titre d'exemple, disons que je veux obtenir le nom de la commande à partir de a $PID
(veuillez noter que ce n'est qu'un exemple, je ne suggère pas que ce soit le moyen le plus simple d'obtenir un nom de commande à partir d'un identifiant de processus - mon vrai problème est avec une autre commande dont je ne peux pas contrôler le format de sortie).
Si je cours, ps
j'obtiens:
PID TTY TIME CMD
11383 pts/1 00:00:00 bash
11771 pts/1 00:00:00 ps
Maintenant je fais ps | egrep 11383
et je reçois
11383 pts/1 00:00:00 bash
Étape suivante: ps | egrep 11383 | cut -d" " -f 4
. La sortie est:
<absolutely nothing/>
Le problème est que cut
coupe la sortie par des espaces simples, et comme ps
ajoute des espaces entre les 2ème et 3ème colonnes pour garder une certaine ressemblance avec une table, cut
choisit une chaîne vide. Bien sûr, je pourrais utiliser cut
pour sélectionner le 7ème et non le 4ème champ, mais comment puis-je savoir, surtout quand la sortie est variable et inconnue au préalable.
Réponses:
Un moyen simple consiste à ajouter une passe de
tr
pour éliminer tous les séparateurs de champ répétés:$ ps | egrep 11383 | tr -s ' ' | cut -d ' ' -f 4
la source
tr
plus léger queawk
Je pense que le moyen le plus simple est d'utiliser awk . Exemple:
$ echo "11383 pts/1 00:00:00 bash" | awk '{ print $4; }' bash
la source
ps | awk "\$1==$PID{print\$4}"
ou (mieux)ps | awk -v"PID=$PID" '$1=PID{print$4}'
. Bien sûr, sous Linux, vous pouvez simplement fairexargs -0n1 </proc/$PID/cmdline | head -n1
oureadlink /proc/$PID/exe
, mais de toute façon ...;
au{ print $4; }
besoin? Le supprimer ne semble avoir aucun effet pour moi sur Linux, juste curieux de son objectifVeuillez noter que l'
tr -s ' '
option ne supprimera aucun espace de début unique. Si votre colonne est alignée à droite (comme avecps
pid) ...$ ps h -o pid,user -C ssh,sshd | tr -s " " 1543 root 19645 root 19731 root
Ensuite, la coupe entraînera une ligne vide pour certains de ces champs s'il s'agit de la première colonne:
$ <previous command> | cut -d ' ' -f1 19645 19731
A moins que vous ne le précédiez d'un espace, évidemment
$ <command> | sed -e "s/.*/ &/" | tr -s " "
Maintenant, pour ce cas particulier de nombres pid (pas de noms), il existe une fonction appelée
pgrep
:Fonctions du shell
Cependant, en général, il est encore possible d'utiliser les fonctions du shell de manière concise, car il y a une chose intéressante à propos de la
read
commande:$ <command> | while read a b; do echo $a; done
Le premier paramètre à lire,
a
sélectionne la première colonne, et s'il y en a plus, tout le reste sera inséréb
. Par conséquent, vous n'avez jamais besoin de plus de variables que le numéro de votre colonne +1 .Donc,
while read a b c d; do echo $c; done
affichera alors la 3e colonne. Comme indiqué dans mon commentaire ...
Une lecture canalisée sera exécutée dans un environnement qui ne transmet pas de variables au script appelant.
out=$(ps whatever | { read a b c d; echo $c; }) arr=($(ps whatever | { read a b c d; echo $c $b; })) echo ${arr[1]} # will output 'b'`
La solution Array
On se retrouve donc avec la réponse de @frayser qui est d'utiliser la variable shell IFS qui par défaut est un espace, pour diviser la chaîne en un tableau. Cela ne fonctionne que dans Bash. Dash et Ash ne le supportent pas. J'ai eu du mal à diviser une chaîne en composants dans un objet Busybox. Il est assez facile d'obtenir un seul composant (par exemple en utilisant awk) et de le répéter pour chaque paramètre dont vous avez besoin. Mais vous finissez par appeler à plusieurs reprises awk sur la même ligne, ou à plusieurs reprises en utilisant un bloc de lecture avec écho sur la même ligne. Ce qui n'est ni efficace ni joli. Alors vous finissez par vous séparer en utilisant
${name%% *}
etc. Vous donne envie de certaines compétences Python car en fait, les scripts shell ne sont plus très amusants si la moitié ou plus des fonctionnalités auxquelles vous êtes habitué ont disparu. Mais vous pouvez supposer que même python ne serait pas installé sur un tel système, et ce n'était pas le cas ;-).la source
echo "$a"
etecho "$c"
cependant.var=$(....... | { read a b c d; echo $c; })
. Cela ne fonctionne que pour une seule (chaîne), mais dans Bash, vous pouvez la diviser en un tableau en utilisantar=($var)
essayer
ps |& while read -p first second third fourth etc ; do if [[ $first == '11383' ]] then echo got: $fourth fi done
la source
Utilisation de variables de tableau
set $(ps | egrep "^11383 "); echo $4
ou
A=( $(ps | egrep "^11383 ") ) ; echo ${A[3]}
la source
Semblable à la solution awk de brianegge, voici l'équivalent Perl:
ps | egrep 11383 | perl -lane 'print $F[3]'
-a
active le mode de partage automatique, qui remplit le@F
tableau avec les données de la colonne.À utiliser
-F,
si vos données sont délimitées par des virgules, plutôt que par des espaces.Le champ 3 est imprimé car Perl commence à compter de 0 au lieu de 1
la source
Obtenir la ligne correcte (exemple pour la ligne n ° 6) se fait avec head and tail et le mot correct (mot n ° 4) peut être capturé avec awk:
command|head -n 6|tail -n 1|awk '{print $4}'
la source
awk NR=6 {print $4}
serait un peu plus efficaceawk NR==6 {print $4}
* doh *Votre commande
ps | egrep 11383 | cut -d" " -f 4
manque un
tr -s
pour serrer les espaces, comme l'explique se détendre dans sa réponse .Cependant, vous voudrez peut-être utiliser
awk
, car il gère toutes ces actions en une seule commande:ps | awk '/11383/ {print $4}'
Ceci imprime la 4ème colonne de ces lignes contenant
11383
. Si vous voulez que cela corresponde11383
s'il apparaît au début de la ligne, vous pouvez direps | awk '/^11383/ {print $4}'
.la source
Au lieu de faire tous ces greps et trucs, je vous conseillerais d'utiliser les capacités ps pour changer le format de sortie.
Vous obtenez la ligne cmmand d'un processus avec le pid spécifié et rien d'autre.
Ceci est conforme à POSIX et peut donc être considéré comme portable.
la source
Bash
set
analysera toutes les sorties en paramètres de position.Par exemple, avec la
set $(free -h)
commande,echo $7
affichera "Mem:"la source
set $(sar -r 1 1)
;echo "${23}"
awk
est la meilleure façon de procéder.bash
et nonawk
.