Avoir les éléments suivants dans l'une de mes fonctions Shell:
function _process () {
awk -v l="$line" '
BEGIN {p=0}
/'"$1"'/ {p=1}
END{ if(p) print l >> "outfile.txt" }
'
}
, donc lorsqu'il est appelé en tant que _process $arg
, $arg
est passé en tant que $1
, et utilisé comme modèle de recherche. Cela fonctionne de cette façon, car Shell se développe $1
à la place du modèle awk! l
peut également être utilisé dans le programme awk, étant déclaré avec -v l="$line"
. Tout va bien.
Est-il possible de la même manière de donner un motif de recherche en tant que variable?
La suite ne fonctionnera pas,
awk -v l="$line" -v search="$pattern" '
BEGIN {p=0}
/search/ {p=1}
END{ if(p) print l >> "outfile.txt" }
'
, comme awk n'interprète pas /search/
comme variable, mais à la place littéralement.
Utilisez l'opérateur ~
De awk, et vous n'avez pas besoin de fournir une expression rationnelle littérale sur le côté droit:
function _process () {
awk -v l="$line" -v pattern="$1" '
$0 ~ pattern {p=1}
END {if(p) print l >> "outfile.txt"}
'
}
Bien que ce soit plus efficace (pas besoin de lire tout le fichier)
function _process () {
grep -q "$1" && echo "$line"
}
Selon le motif, vous voudrez peut-être grep -Eq "$1"
awk -v pattern="$1" '$0 ~ pattern'
A un problème dans la mesure où awk
développe les séquences d'échappement ANSI C (comme \n
pour la nouvelle ligne, \f
pour le flux de formulaires, \\
pour la barre oblique inverse, etc.) dans $1
. Cela devient donc un problème si $1
contient des barres obliques inverses courantes dans les expressions régulières (avec GNU awk
4.2 ou supérieur, valeurs commençant par @/
et se termine par /
, sont également un problème ). Une autre approche qui ne souffre pas de ce problème est de l'écrire:
PATTERN=$1 awk '$0 ~ ENVIRON["PATTERN"]'
La gravité de la situation dépendra de l'implémentation de awk
.
$ nawk -v 'a=\.' 'BEGIN {print a}'
.
$ mawk -v 'a=\.' 'BEGIN {print a}'
\.
$ gawk -v 'a=\.' 'BEGIN {print a}'
gawk: warning: escape sequence `\.' treated as plain `.'
.
$ gawk5.0.1 -v 'a=@/foo/' BEGIN {print a}'
foo
Tous les awk
fonctionnent de la même manière pour les séquences d'échappement valides:
$ a='\\-\b' awk 'BEGIN {print ENVIRON["a"]}' | od -tc
0000000 \ \ - \ b \n
0000006
(contenu de $a
passé tel quel)
$ awk -v a='\\-\b' 'BEGIN {print a}' | od -tc
0000000 \ - \b \n
0000004
(\\
changé en \
et \b
changé en caractère de retour arrière).
Essayez quelque chose comme:
awk -v l="$line" -v search="$pattern" 'BEGIN {p=0}; { if ( match( $0, search )) {p=1}}; END{ if(p) print l >> "outfile.txt" }'
Non, mais vous pouvez simplement interpoler le motif dans la chaîne entre guillemets doubles que vous passez à awk:
awk -v l="$line" "BEGIN {p=0}; /$pattern/ {p=1}; END{ if(p) print l >> \"outfile.txt\" }"
Notez que vous devez maintenant échapper au littéral awk entre guillemets doubles, mais c'est toujours le moyen le plus simple d'y parvenir.