Je veux savoir comment utiliser grep
pour afficher toutes les lignes qui commencent et se terminent par le même caractère.
POSIXly:
pattern='\(.\).*\1 .' grep -x -- "$pattern" file
Cela ne fonctionnera pas si la ligne commence ou se termine par un caractère d'octet invalide. Si vous voulez couvrir ce cas, vous pouvez append LC_ALL=C
, bien que LC_ALL=C
fonctionne qu'avec des données de caractères sur un seul octet.
perl6
semble être le meilleur outil, si vous l'avez dans votre boite:
$ printf '\ue7\u301 blah \u107\u327\n121\n1\n123\n' | perl6 -ne '.say if m/^(.).*$0$/ || /^.$/' ḉ blah ḉ 121 1
Bien qu'il s'étouffe encore sur les caractères invalides.
Notez que perl6
va modifier votre text en le convertissant en formulaire NFC
:
$ printf '\u0044\u0323\u0307\n' | perl6 -pe '' | perl -CI -ne 'printf "U+%04x\n", ord for split //' U+1e0c U+0307 U+000a $ printf '\u0044\u0323\u0307\n' | perl -pe '' | perl -CI -ne 'printf "U+%04x\n", ord for split //' U+0044 U+0323 U+0307 U+000a
En interne, perl6
stocke la string sous forme NFG
(stand for Normalization Form Grapheme
), qui est perl6
inventé façon de traiter correctement les graphèmes non précomposés:
$ printf '\u0044\u0323\u0307\n' | perl6 -ne '.chars.say' 1 $ printf '\u0044\u0323\u0307\n' | perl6 -ne '.codes.say' 2
Pas grep mais awk:
awk -F "" 'NF && $1 == $NF'
Ces cas spéciaux sont traités:
Un FS vide divise l'logging en un seul caractère par gawk
, mawk
et busybox
awk
(octets, pas des caractères pour les deux derniers), mais n'est pas standard et ne fonctionne pas dans les implémentations de awk
dérivée de l'original par A , W et K comme sur les BSD et les Unices commerciaux. Plus portable mais plus à taper:
awk '/./ && substr($0,1,1) == substr($0,length)'
grep -xe '\(.\).*\1' -e .
Exemple:
$ printf '%s\n' il y était cet été | grep -xe '\(.\).*\1' -e . y été
-x
est pour une correspondance exacte (correspondance sur toute la ligne). \1
étant une reference arrière au caractère capturé dans \(.\)
. Nous ajoutons un -e .
pour prendre soin du cas particulier d'une ligne contenant un seul caractère.
Il suppose que l'input contient du text valide dans les parameters régionaux en cours.
La correspondance est sur le caractère et non sur l' octet (les é en UTF-8 sont les deux octets 0xc3 0xa9 par exemple), ni grappe graphem (cela ne marcherait pas si ces é étaient écrits dans leur forme décomposée avec e
suivi de U + 0301 combinant un accent aigu par exemple).
Pour travailler sur les grappes de graphes, avec un grep
qui supporte -P
pour PCRE:
$ printf 'e\u0301te\u0301\n' | grep -xPe '(\X).*\1|\X' été
Cela suppose que la décomposition est la même pour les deux grappes, par exemple un ḉ
exprimé comme c
U+0301
U+0327
ne correspondrait pas à celui exprimé par c
U+0327
U+0301
ou ć
( U+0107
) U+0327
ou ç
( U+00E7
) U+0301
ou ḉ ( U+1E09
). Pour cela, vous devez faire le contrôle sur un formulaire normalisé:
$ printf '\ue7\u301 blah \u107\u327\n' | perl -MUnicode::Normalize -C -ne ' print if /^\X$/ || NFC($_) =~ /^(\X).*\1$/' ḉ blah ḉ
Alternative rapide à python2:
python -c 'import sys;[sys.stdout.write(l) for l in sys.stdin if len(l)>1 and l.rssortingp("\n").endswith(l[0])]' < input.txt
Exemple:
$ python -c 'import sys;[sys.stdout.write(l) for l in sys.stdin if len(l)>1 and l.rssortingp("\n").endswith(l[0])]' < input.txt | cat -A nathan$ ookie $ a line a$