Creo que puedo hacerlo en un solo programa awk
, como se muestra a continuación. A primera vista, parecerá más largo de lo que realmente es, porque usa nombres de variables descriptivos largos y es consciente de liberar memoria inmediatamente cuando sea posible.
awk
tiene potentes funciones de clasificación nativas incorporadas, por lo que no es necesario conectarse a un programa externo.
awk
Las funciones asort
y asorti
también toman un tercer argumento opcional, siendo el método de clasificación , que puede ser cosas como @ind_num_asc
, @ind_num_desc
, @ind_num_asc
, @ind_num_desc
, etc. para varias formas de clasificar en orden ascendente o descendente. Como de costumbre, consulte la página man
.
El programa está repleto de declaraciones delete
para tener en cuenta el uso de la memoria, lo que podría convertirse en un problema a medida que crecen los conjuntos de datos.
Es una pena que no nos haya dado datos de entrada de muestra para jugar. Pasé un buen rato codificando esto, pero solo Dios sabe qué tan cerca está de trabajar sin datos de entrada, así que trate el código a continuación como una prueba -de -concepto que puede necesitar trabajo para, um, trabajo. La conclusión básica -es que el método más eficiente es probablemente todo interno a un solo programa awk
.
hammer host list \
| awk -F'|' ' \
BEGIN {i=0}
/RHEL Server/ {
unsorted_count[$3]++
unsorted_list[i++]=$3"|"$2
}
END {
printf "\nLinux Versions Grouped by Count\n\n"
i=0
for (release in unsorted_count)
count_list[i++]=unsorted_count[release]"\t"release
delete unsorted_count
n=asort(count_list,sorted_count)
delete count_list
for (i=1; i<=n; i++)
printf "%s\n", sorted_count[i]
delete sorted_count
printf "\n\nLinux Versions and Hostnames\n\n"
i=0
for (hostname in unsorted_list)
host_list[i++]=unsorted_list[hostname]" | "hostname
delete unsorted_list
n=asort(host_list,sorted_list)
delete host_list
for (i=1; i<=n; i++)
printf "%s\n", sorted_list[i]
}'
Чтобы узнать, что это за персонаж:
less sourcefile
или
od -c sourceFile
для более подробного просмотра.
Если речь идет о данных json, (известно, что пакет python json
сообщает об ошибке ), вы можете определить, какая строка json содержит управляющие символы, с помощью:
perl -Mcharnames=:full -C -l -0777 -ne '
while (/"(?:\\.|[^"])*"/g) {
my $offset = $-[0];
my $string = $&;
@ctrl = map {charnames::viacode(ord($_))} $string =~ /\p{PosixCntrl}/g;
if (@ctrl) {
print "Offset: $offset, String: $string, Ctrl: ". join "+", @ctrl
}
}' file.json
На примере файла file.json
здесь:
$ python -c 'import json; import os; print(json.load(file("file.json")))'
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib/python2.7/json/__init__.py", line 291, in load
**kw)
File "/usr/lib/python2.7/json/__init__.py", line 339, in loads
return _default_decoder.decode(s)
File "/usr/lib/python2.7/json/decoder.py", line 364, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python2.7/json/decoder.py", line 380, in raw_decode
obj, end = self.scan_once(s, idx)
ValueError: Invalid control character at: line 1 column 22 (char 21)
А приведенный выше код perl
возвращает:
Offset: 19, String: "a b
c", Ctrl: CHARACTER TABULATION+LINE FEED
Вы можете видеть, что управляющий символ, на который жалуется python, — это TAB один, через 2 символа после начала этой строки "..."
. Обратите внимание, что perl
сообщает об удалении в количестве символов, тогда как python сообщает о них в количестве байтов.
Для поиска определенного символа
grep
и sed
не поддерживают обратную косую черту для управляющих символов.(sed
использует обратную косую черту для регулярных выражений обратных ссылок . )Если вы используете bash
, он может преобразовать последовательность обратной косой черты в фактический управляющий символ перед передачей в эти (или любые )программы:
$ grep $'\t' file
$ sed -n /$'\t'/p file
$ # or change to l (ell) to visibly show the control character(s)
$ sed -n /$'\t'/l file
OTOH awk
поддерживает эту нотацию с возможностью переноса:
$ awk '/\t/' file
Для поиска любого управляющего символа
Как grep
, так и sed
могут выполнять поиск по классу/диапазону дополненных символов, который будет находить строки, содержащие любой символ, который не является «печатным» (графическим изображением или пробелом )ASCII-символ. (Символы новой строки, которые разделяют строки в файле, не обрабатываются как в строках и, таким образом, не удовлетворяют этому соответствию. Однако,если у вас есть файл с CRLF в стиле Windows или telnet/SMTP/и т. д., CR будет совпадать в каждой строке, что делает этот метод менее полезным.)
$ export LANG=C # use an ASCII or at least single-byte locale; this is the simplest one
$ grep '[^ -~]' file
$ sed -n '/[^ -~]/p' file
$ # or better (see below)
$ sed -n '/[^ -~]/l' file
Чтобы отобразить , какой управляющий символ (s )является (присутствует )либо во всем файле, либо в выбранной строке (s ), в дополнение к опции , предоставленные SHawarden , вы также можете использовать:
$ sed -n l [file] # that's ell not one; can merge into the selection as above
$ cat -vT [file]
$ # both read stdin if not given a filename
$ # and thus can be piped from a selection command above
Обратите внимание, что в некоторых из этих дисплеев используется обратная косая черта, по крайней мере, для некоторых символов(\t
= табуляция, \b
= пробел ), в то время как в других используется знак «вставки» (, который в древние времена был 'стрелка вверх' )обозначение(^I
= табуляция, ^H
= возврат ). См. любую диаграмму ASCII для соответствий, отметив, что знак вставки/стрелка вверх представляет либо вычитание, либо добавление шестнадцатеричного числа 40 (, равного восьмеричному 100 ).