У меня есть папка, содержащая несколько файлов, и из каждого файла мне нужно 1) извлечь все строки, содержащие элементы из заранее заданного списка слов; 2) добавить имя файла к этой строке 3) разделить извлеченную строку на две отдельные строки, удалив некоторое содержимое между ними.
Это содержимое файлов, из которых мне нужно извлечь:
freq +fchi +t*CHI +s"m|v"
Fri Feb 24 10:24:17 2017
freq (08-Jan-2016) is conducting analyses on:
ONLY speaker main tiers matching: *CHI;
and those speakers' ONLY dependent tiers matching: %MOR;
****************************************
From file <sarah004.cha>
Speaker: *CHI:
2 v|eye-3S
1 v|get
2 v|get&PAST
1 v|go&PAST
1 v|help
2 v|ride
3 v|see
1 v|toe-3S
------------------------------
8 Total number of different item types used
13 Total number of items (tokens)
0.615 Type/Token ratio
Пример списка слов, которые я ищу, - см. | Знать | смотреть (фактический список намного длиннее, около 25 слов).
В итоге я хочу получить следующее:
sarah004.cha 3 see
sarah006.cha 3 know
sarah010.cha 1 look
sarah010.cha 2 see
...
Итак, помимо извлечения строк, содержащих указанные слова, я бы также разделил число и слово и удалил v |.
Некоторые файлы в каталоге могут не содержать ни одного слова из списка, другие могут содержать многие слова из списка.
Я не уверен, что смогу сделать это с помощью sed; Я попробовал это в качестве отправной точки (просто извлекать любые строки со счетчиками), и он не завершился:
sed '/From file/{s/.*<\(.*\)>/\1/;h
}
/^ [0-9] v|/!d
s/.*= //;H;x' ./* | paste - - > sarahverbcounts.txt
Я бы хорошо сделал это в несколько шагов, хотя я уверен, что это можно сделать с помощью одной команды / сценария и я просто не знаю как. Я думаю, что Perl справится с этим, но я не знаю синтаксиса (я пробовал использовать найденный мной пример perl и не мог понять, как правильно изменить его для своих целей).Возможно, мне нужно попробовать это в Python, что позволило бы мне указать список слов, но я не знаком с тем, как заставить Python перебирать все файлы в каталоге один за другим и все они записываются в один и тот же выходной файл ( Я просмотрел примеры, но я их не совсем понимаю). Любые советы приветствуются (и, если возможно, объяснения того, как работает ваше решение, были бы замечательными, потому что я достаточно новичок в этом, я не всегда могу разбирать полезные ответы, которые мне дают).
Поместите список слов для поиска в файл с именем words.txt
а затем запустите:
grep -Hf words.txt files.* | sed 's/:/ /;s/v|/ /'
Вы можете сделать это разными способами, как показано. Шаблоны сохраняются по одному на строку в файле списка.
Примечание. Мы отличаем файл шаблонов от остальных файлов данных (предположительно, ваших файлов * cha
) с помощью различных уловок в bash, perl и sed.
В случае "sed" шаблоны хранятся в точечном файле, также известном как скрытые файлы, &
с добавлением "." чтобы помочь коду "sed" отличить файл шаблона
от обычного файла данных. Это WA для sed, поскольку он не имеет, как в
awk, концепции "FNR".
grep -E -f ./.your_patterns_listfile ./* |
sed -e 's/://' -e 's/v|//'
find . -maxdepth 1 -type f -name '*' -exec \
perl -wMstrict -Mvars='*pat' -lne '
BEGIN { ($pat) = @ARGV; }
if ( $pat ne $ARGV ) {
@pat = map { quotemeta } keys %pat unless @pat;
next unless /^From file [<]/ .. /^--*/;
my $cha;
/^From file [<]([>]*)[>]/ and $cha = $1;
for my $pat ( @pat ) {
/^\s+ (\d+) \s+ v[|] ($pat) $/x and print(join("\t",$ARGV,$1,$2)),last
}
} else {
$pat{$_}++;
}
' ./your_patterns_listfile {} +
echo '.' >> ./.your_patterns_listfile
find . -maxdepth 1 -type f -name '*' -exec \
sed -e '
1{
:pats
N
/\n\.$/!bpats
s///;h;d
}
/^From file </!d
$d;N
/\n[ ]*\([1-9][0-9]*\)[ ]v|/{
s//\n\1\t|/;s/$/|/
G;s/\n/&&/;s/$/\n/
/\n\n[1-9][0-9]*\t|\([^|]*\)|.*\n\1\n/{
s/^From file <\([^>]*\)>\n\n\([1-9][0-9]*\)\t|\([^|]*\)|/\1\t\2\t\3\n&/
P;s/\n\n.*//;D
}
}
s/\n.*//;s/^/\n/;D
' ./.your_patterns_listfile {} +
find . -type f -name '*' ! -name 'your_patterns_listfile' -exec \
sh -c '
shift $1
flag=
eval "`echo '\''readonly NL=qsq'\'' | tr '\''qs'\'' '\''\047\012'\''`"; # newline
pats=$(< $1); shift
cat "$@" |
while IFS= read -r line
do
case $line in
"From file <"* )
cha=${line#*"<"}
cha=${cha%">"}
unset flag
continue
;;
*[0-9]*v\|* )
pat=${line#*"|"}
num=${line%%"v"*}
num=${num//[ ]/}
case $pats in
"$pat" | *"$NL$pat$NL"* | "$pat$NL"* | *"$NL$pat" )
${flag+":"} printf "%s\t" "$cha" "$num" "$pat"
${flag+":"} echo
;;
esac
;;
'' | *[!-]* )
:
;;
* )
flag=
;;
esac
done
' 2 1 ./your_patterns_listfile {} +
Может быть что-то вроде этого:
egrep '^\s+[0-9]+\s+v\|([0-9a-zA-Z-]+)$' files* | sed -e 's/v|//g'