J'essaie de trouver la réponse à cette question depuis un certain temps. J'écris un script rapide pour exécuter une commande basée sur la sortie de awk.
ID_minimum=1000
for f in /etc/passwd;
do
awk -F: -vID=$ID_minimum '$3>=1000 && $1!="nfsnobody" { print "xfs_quota -x -c 'limit bsoft=5g bhard=6g $1' /home "}' $f;
done
Les problèmes sont que l' -c
argument prend une commande entre guillemets simples et je ne peux pas comprendre comment échapper correctement cela et aussi qui $1
ne se développe pas dans le nom d'utilisateur.
Essentiellement, j'essaie simplement de le faire sortir:
xfs_quota -x -c 'limit bsoft=5g bhard=6g userone' /home
xfs_quota -x -c 'limit bsoft=5g bhard=6g usertwo' /home
etc...
awk
Réponses:
Pour exécuter la commande
xfs_quota -x -c 'limit bsoft=5g bhard=6g USER' /home
pour chacunUSER
dont l'UID est au moins$ID_minimum
, envisagez d'abord d'analyser ces utilisateurs, puis exécutez réellement la commande, plutôt que d'essayer de créer une chaîne représentant la commande que vous souhaitez exécuter.Si vous créez la chaîne de commande, vous devrez le faire
eval
. C'est délicat et facile de se tromper. Il est préférable d'obtenir simplement une liste de noms d'utilisateurs, puis d'exécuter la commande.Notez qu'il n'y a aucun besoin réel de guillemets simples autour de l'argument après
-c
. Ici, j'utilise des guillemets parce que je veux que le shell développe la$user
variable qui contient les valeurs extraites parawk
.J'utilise
${ID_minimum:-1000}
pour donner la valeur à lamin
variable dans laawk
commande. Cela se développera à la valeur de$ID_minimum
, ou à1000
si cette variable est vide ou non définie.Si vous le vouliez vraiment , vous pourriez faire en sorte que la boucle ci-dessus imprime les commandes au lieu de les exécuter:
Notez à nouveau que l'utilisation de guillemets doubles dans la chaîne de commande émise (au lieu de guillemets simples) ne perturberait en aucun cas un shell si vous exécutiez les commandes générées à l'aide
eval
ou par d'autres moyens. Si cela vous dérange, permutez simplement les guillemets simples et doubles dans le premier argumentprintf
ci-dessus.la source
getent
(sur le bureau, de toute façon), et la question n'est pas étiquetée "linux"./home
n'est pas vraiment utilisé sur macOS (il est là, mais généralement vide).C'est un peu idiot car il n'y a vraiment pas de boucle avec une seule valeur.
Mais le problème semble être d'imprimer des guillemets simples à partir de awk. Vous pouvez les échapper dans le shell, mais vous pouvez également utiliser des barres obliques inversées dans awk pour les imprimer. est le caractère avec la valeur numérique OOO (en octal ), donc est . Ce serait donc une façon de procéder:
\OOO
\047
'
Vous pouvez utiliser l'échappement similaire en hexadécimal,
\x27
mais il peut être mal interprété dans certaines implémentations si le caractère suivant est un chiffre hexadécimal valide. (Et bien sûr, j'ai supposé ASCII ou un jeu de caractères compatible ASCII, par exemple UTF-8.)la source
l
n'est pas un chiffre hexadécimal, mais"\x27df\n"
serait traité comme"\x27" "df"
dans awkbox ou mawk de busybox mais comme"\xdf"
(0x27df
converti en caractère 8 bits) dans awk et gawk d'origine (c'est la raison pour laquelle POSIX ne le spécifie pas\xHH
). Les octales (\047
) n'ont pas le même problème et sont POSIX. Dans tous les cas, cela suppose un système ASCII (une hypothèse raisonnable de nos jours).Utilisez l'
-f -
option awk pour prendre le script de stdin et un document ici:la source
Ça l'a fait.
la source
'\''
ou'"'"'
. Les deux fonctionnent, les deux semblent ennuyeux.C'est une horrible loge, mais c'est rapide et facile ...
la source
Cela me semble être une opportunité idéale pour vous en employer
xargs
(ou GNU Parallel ):L'avantage d'utiliser
xargs
ouparallel
est que vous pouvez simplement supprimer leecho
lorsque vous êtes prêt à exécuter la commande pour de vrai (éventuellement en la remplaçantsudo
si nécessaire).Vous pouvez également utiliser les options de ces utilitaires
-p
/--interactive
(ce dernier est uniquement GNU) ou--dry-run
(parallel
uniquement), pour obtenir une confirmation avant d'exécuter chacun, ou simplement pour voir ce qui fonctionnerait, avant de l'exécuter.La méthode générale utilisée ci-dessus devrait fonctionner sur la plupart des Unix et ne nécessite aucune
xargs
option spécifique à GNU . Les guillemets doubles ne doivent être « échappé » de sorte qu'ils apparaissent littéralement dans la sortie. Notez que la "chaîne de remplacement"{}
dansxargs -I{}
peut être tout ce que vous préférez et-I
implique-L1
(exécutez une commande par ligne d'entrée plutôt que de les regrouper).GNU Parallel ne nécessite pas l'
-I
option ({}
c'est la chaîne de remplacement par défaut), et vous donne le bonus instantané d'exécuter de nombreux travaux en parallèle, même si vous ne voulez pas prendre la peine de vous renseigner sur l' une de ses autres fonctionnalités .En remarque, je ne suis même pas sûr si
xfs_quota
l'-c
option est censée être utilisée comme ça, bien que je n'ai pas de systèmes de fichiers XFS à portée de main. Vous n'avez peut-être même pas eu besoin de traiter une chaîne entre guillemets en premier lieu (sauf si vous vous attendez à des noms d'utilisateur avec des espaces, ce qui, je suppose, est possible), car il semble que vous pouvez donner plusieurs-c
options sur la même ligne de commande, selon à la page de manuel incluse avecxfsprogs
4.5.quelque chose.la source
Avec GNU Parallel, vous pouvez faire:
Explication:
--colsep :
Fractionner sur:-q
ne pas fractionner la commande sur les espaces (garder le '...' comme une seule chaîne){=1 ... =}
Évaluer cette expression perl sur le premier argument de la ligne$_ eq "nfsnobody" and skip();
Si la valeur == nfsnobody: sauter$arg[3] <= 1000 and skip();
Si argument3 <= 1000: sauterla source