Поиск текстового файла столбцом

Disk Usage Analyzer подсчитывает сумму пространства, используемого всеми файлами. Что-то как df спрашивает файловая система, сколько пространства используется. Эти две суммы могут очень отличаться в зависимости от, например, сколько удаленный, но все еще открывают, файлы находятся в файловой системе.

например, если Вы делаете что-то вроде этого:

$ dd if=/dev/zero of=largefile bs=1M count=1024
$ python -c 'import time; x = open("largefile'); time.sleep(600)' &
$ rm largefile

Вы будете видеть, что 1 ГБ пространства все еще показывают df, но не Disk Usage Analyzer. Это вызвано тем, что, в то время как файл все еще открыт, он на самом деле не удален из диска. Когда сценарий Python закончится, файловая система освободит пространство.

Я не уверен, объясняет ли вышеупомянутое Ваш 4.4G 9G несоответствие, хотя!

4
25.06.2012, 13:46
8 ответов

Это не похоже, я не попробовал прежде, чем спросить..., вот моя попытка..., но это выглядит слишком сложным мне. Игнорируйте логику, которая обрабатывает грязные файлы корректно, это не была часть вопроса, и это не фокус текстового поиска так или иначе. Это именно так происходит, который файлы, которые я имею иногда, не запускают с "ЗАГОЛОВКА", но с небольшого количества мусора, со всей остальной частью данных, бывших прекрасных абсолютно, всегда.

#!/bin/bash

file_to_scan="${1}"
name_to_lookup="${2}"

ASSUME_FIRST_LINE_IS_HEADER="false" # Sometimes input files begin with spurious lines

FILE_HEADER_REGEX='^\[#\][[:blank:]]+OWNER_NAME[[:blank:]]+NAME[[:blank:]]+SIZE\s*$'

FIELD_HEADER_NAME=' NAME'
FIELD_HEADER_SIZE=' SIZE'

if [ "$ASSUME_FIRST_LINE_IS_HEADER" == "true" ]; then
    header_line=$(head -n 1 "${file_to_scan}")
else
    header_line="$(
        grep \
            --colour=never \
            --extended-regexp \
            "${FILE_HEADER_REGEX}" \
            "${file_to_scan}"
        )"
fi

colstartend=($(
    printf "${header_line}" \
        | \
        awk \
            -v name="${FIELD_HEADER_NAME}" \
            -v size="${FIELD_HEADER_SIZE}" \
            '{
                 print index($0, name)+1;
                 print index($0, size);
             }'
))

sed -E "1,/${FILE_HEADER_REGEX}/d" "${file_to_scan}" \
    | \
    awk \
        -v name_to_lookup="${name_to_lookup}" \
        -v colstart="${colstartend[0]}" \
        -v offset="$(( ${colstartend[1]} - ${colstartend[0]} ))" \
        '{
             name_field = substr($0, colstart, offset);
             sub(/ *$/, "", name_field);
             if (name_field == name_to_lookup) {
               print substr($1, 2, length($1)-2)
             }
         }'
0
27.01.2020, 20:51
  • 1
    , я думал об использовании grep - байтовое смещение для получения запуска и окончания номеров столбцов для Поля имени, но байтов не является символами, и символы здесь могут быть Unicode и иметь больше байтов на символ... Хм... –  Robottinosino 25.06.2012, 13:52

Хорошо, если бы длина столбцов не известна, я переключился бы на более мощный язык, чем удар:

#!/usr/bin/perl
use warnings;
use strict;

my $string = shift;
open my $FH, '<', '1.txt' or die $!;
my $first_line = <$FH>;
my ($before, $name) = $first_line =~ /(.* )(NAME *)/;
my $column = length $before;
$string .= ' ' x (length($name) - length $string);     # adjust the length of $string
while (<$FH>) {
    if ($column == index $_, $string, $column) {
        /^\[([0-9]+)\]/ and print "$1\n";
    }
}
3
27.01.2020, 20:51
  • 1
    Хороший сценарий Perl, но к сожалению я не знаю Perl, и было бы трудно поддержать это... –  Robottinosino 25.06.2012, 12:52
  • 2
    @Robottinosino: должно быть довольно легко переписать его в Python или любом другом языке сценариев, который легче поддержать для Вас. –  choroba 25.06.2012, 13:14
  • 3
    Python является золотым для меня, и я соглашаюсь с Вами: вероятно, лучше использовать абсолютный язык сценариев здесь. Что я должен пройти здесь, тем не менее, просто старое семейство кошки, главы, хвоста, awk, sed, grep, сокращения, и т.д. –  Robottinosino 25.06.2012, 13:46

Если ширина поля является постоянной - т.е. формат файла, Вы показали с шириной поля, которую Вы имеете, в их максимуме - можно использовать GNU awk (gawk(1)) и набор FIELDWIDTHS переменная для использования зафиксированного парсинга ширины:

gawk -v searchstr="Ideas worth zero" -- '
    BEGIN { FIELDWIDTHS="6 15 27 5" }  # assuming the final field width is 5
    # Pre-process data
    {
        gsub(/[^[:digit:]]/, "", $1)  # strip out non-numbers
        for (i = 2; i <= NF; i++)
            gsub(/[[:space:]]*$/, "", $i)  # strip trailing whitespace
    }
    # match here
    $3 == searchstr { print $1 }
' file.txt

Можно перенести это в сценарий оболочки или функцию и параметризовать searchstr (-v searchstr="$1").

Однако, если поля имеют переменную ширину - т.е. если данные изменяются, ширина полей может измениться - необходимо будет быть немного более умными и динамично определить ширину поля от осмотра первой строки. Учитывая, что одно поле называют OWNER_NAME, с помощью подчеркивания я предполагаю, что пробелы не присутствуют в именах полей, таким образом, я могу предположить, что пробел разделяет имена полей.

С определенным, можно заменить BEGIN... строка с этим кодом:

NR == 1 {
    for (i = 2; i <= NF; i++)
        FIELDWIDTHS=FIELDWIDTHS index($0" ", " "$i" ")-index($0" ", " "$(i-1)" ") " "
    FIELDWIDTHS=FIELDWIDTHS "5"  # assuming 5 is the width of the last field
    next
}

Это посмотрит на поля на первой строке и вычислит ширину поля путем вычисления различия между положениями последующих полей для второго к последнему полю. Я предположил, что ширина последнего поля равняется 5, но я думаю, что можно просто поместить большое количество там, и это будет работать с тем, что перенесено.

Мы должны искать пространство прежде и после имени, чтобы гарантировать, чтобы мы не находили NAME внутри OWNER_NAME (или если было названное поле OWNER), и вместо этого соответствуйте целому полю (мы также должны добавить пространство к $0 для обеспечения мы можем соответствовать пространству в конце, даже если не было ни одного там).

Вы могли стать более необычными так, чтобы можно было запросить именем поля вместо того, чтобы соответствовать только на $3, но я оставлю это Вам.

3
27.01.2020, 20:51
  • 1
    Кажется мне как Вы, делают большую работу даже для случаев, в которых там не идет ни в какое сравнение? Например, Вы обрезаете пробел на каждом поле даже на несогласующем отрезке длинной линии? Вы очищаете первое поле (" [#]") априорно, даже если Вы только используете его на соответствии? Мне очень понравился код, который вычисляет ШИРИНУ ПОЛЯ, и я узнал о некотором awk из него, но... aren'you снова выполняющий это вычисление для всех полей, где единственным, в длине которого Вы действительно нуждаетесь, является "ИМЯ" один? –  Robottinosino 25.06.2012, 13:39
  • 2
    @Robottinosino: Я делал это немного более общим, чем это должно было быть так, чтобы Вы могли легко соответствовать на различных полях, если бы Вы должны были. Я нахожу, что это делает более ясным разделить очистительный код от фактического кода соответствия (бизнес-логика, так сказать). Если у Вас есть очень большой набор данных, и дополнительная ненужная обработка является значительной, любой ценой, оптимизируйте дополнительную работу. –  camh 25.06.2012, 14:27
 $ cat test
[#]     OWNER_NAME      NAME    SIZE
[6]     Robottinosino   Software        200
[42]    Robottinosino   Ideas worth zero        188
[12]    Robottinosino   Ideas worth zero or more        111
[13]    I am Batman     Hardware        180
[25]    Robottinosino   Profile Pictures        170

 $ cat test.sh
#!/bin/bash -
awk -F"\t" '(NR<=1){for(i=1;i<NF;i++) if(toupper("'$1'")==toupper($i)) field=i;} (toupper($field) == toupper("'"$2"'")){print $1}'

 $ cat test | ./test.sh NAME "Ideas worth zero"
[42]

Я не уверен, что разделитель является вкладкой. Но довольно легко изменить его с sed. Например, sed 's/\s\s+/\t/g' сделает задание.

Также можно указать любое другое поле, не только NAME. Это найдет само число правого столбца.

В случае, если Вам будет нужен только третий сценарий столбца, будет намного легче.

PS. Я использовал его в своем собственном проекте, поэтому это кажется, имеет вполне больше функциональности, в которой Вы нуждаетесь.

upd. из-за разделителя не является строкой запуска изменения вкладки к

 cat test | sed 's/\s\s\+/\t/g' | ./test.sh NAME "Ideas worth zero"

Это работает прекрасное на моем сайте.

1
27.01.2020, 20:51
  • 1
    , первое не имеет вкладки ('\t') как разделитель, к сожалению. –  Robottinosino 25.06.2012, 11:08
  • 2
    , я обновил ответ для устранения проблемы разделителя. –  rush 25.06.2012, 13:10
  • 3
    , если бы какое-либо поле содержит двойной интервал, это повредилось бы, не так ли? например, имя Владельца: "Я - просторное имя пользователя". Просто глядя на него, не кажется, что "просто замена разделителя" таким образом тривиальна, к сожалению... исправьте меня, если я неправ, я могу быть :) –  Robottinosino 25.06.2012, 13:50
  • 4
    Да, к сожалению, Вы правы. =) –  rush 25.06.2012, 14:01
  • 5
    К вашему сведению, -F может взять полный regex, таким образом, Вы не должны даже использовать sed. –  Kevin 25.06.2012, 14:45
 $ cat test
[#]     OWNER_NAME      NAME    SIZE
[6]     Robottinosino   Software        200
[42]    Robottinosino   Ideas worth zero        188
[12]    Robottinosino   Ideas worth zero or more        111
[13]    I am Batman     Hardware        180
[25]    Robottinosino   Profile Pictures        170

 $ cat test.sh
#!/bin/bash -
awk -F"\t" '(NR<=1){for(i=1;i<NF;i++) if(toupper("'$1'")==toupper($i)) field=i;} (toupper($field) == toupper("'"$2"'")){print $1}'

 $ cat test | ./test.sh NAME "Ideas worth zero"
[42]

Я не уверен, что разделитель является вкладкой. Но довольно легко изменить его с sed. Например, sed 's/\s\s+/\t/g' сделает задание.

Также можно указать любое другое поле, не только NAME. Это найдет само число правого столбца.

В случае, если Вам будет нужен только третий сценарий столбца, будет намного легче.

PS. Я использовал его в своем собственном проекте, поэтому это кажется, имеет вполне больше функциональности, в которой Вы нуждаетесь.

upd. из-за разделителя не является строкой запуска изменения вкладки к

 cat test | sed 's/\s\s\+/\t/g' | ./test.sh NAME "Ideas worth zero"

Это работает прекрасное на моем сайте.

1
27.01.2020, 20:51

Вероятно, самое простое для фильтрации строк сначала 'Идеями, стоящими нуля, затем бросающего строки '... или больше':

grep 'Ideas worth zero' | grep -v 'Ideas worth zero or more'

И получить число от того канала вход в:

cut -d' ' -f1 | tr -d ']['

Который сокращает первое поле (разграниченный пространством) и удаление squeare скобок.

Лучше всего был бы к тому, если можно немного изменить формат файла таким способом, которым он идет с надлежащими разделителями полей.

0
27.01.2020, 20:51
  • 1
    Это "grep-v" приближается к масштабу на случаях как 'Идеи, стоящие нуля и немного', 'Идеи, стоящие нуля или чего-то как этот', 'Идеи работают нулевая запятая fourtytwo', и т.д.? –  Robottinosino 25.06.2012, 11:04
  • 2
    Yeap. Но только в случае, если Вы укажете их всех =) –  rush 25.06.2012, 11:06

Вероятно, самое простое для фильтрации строк сначала 'Идеями, стоящими нуля, затем бросающего строки '... или больше':

grep 'Ideas worth zero' | grep -v 'Ideas worth zero or more'

И получить число от того канала вход в:

cut -d' ' -f1 | tr -d ']['

Который сокращает первое поле (разграниченный пространством) и удаление squeare скобок.

Лучше всего был бы к тому, если можно немного изменить формат файла таким способом, которым он идет с надлежащими разделителями полей.

0
27.01.2020, 20:51

Это может помочь Вам:

function my_command () {
    sed -n $(cut -b22-48 1.txt |
        grep -n "$1"' *$' |
        cut -f1 -d: )p 1.txt \
            | cut -d' ' -f1 | tr -d ']['
}

Это сокращает только соответствующий столбец из входа, ищет номер строки, где строка появляется, затем проводит эту строку и только сохраняет число в первом столбце от него.

0
27.01.2020, 20:51
  • 1
    К сожалению, ширина столбцов не известна прежде, чем запустить скрипт (т.е. они автоматически корректируются для установки полям, которые содержат строки переменных длин), –  Robottinosino 25.06.2012, 11:11

Теги

Похожие вопросы