#bash #for-loop #grep
#bash #for-цикл #grep
Вопрос:
Мне нужен цикл, который может находить букву, которой чаще всего заканчиваются слова на нескольких языках, и выводить данные в столбцах. Пока у меня есть
count="./wordlist/french/fr.txt ./wordlist/spanish/es.txt ./wordlist/german/de.$
lang="French Spanish German Portuguese Italian"
(
echo -e "Language Letter Count"
for i in $count
do
(for j in {a..z}
do
echo -e "LANG" $j $(grep -c $j> $i)
done
) | sort -k3 -rn | head -1
done
) | column -t
Я хочу, чтобы она выводилась, как показано:
Language Letter Count
French e 196195
Spanish a 357193
German e 251892
Portuguese a 217178
Italian a 216125
Вместо этого я получаю:
Language Letter Count
LANG z 0
LANG z 0
LANG z 0
LANG z 0
LANG z 0
Файлы слов имеют формат:
Word Freq(#)
где слово и его частота разделены пробелом.
Это означает, что у меня есть 2 проблемы; Во-первых, grep
команда не обрабатывает аргумент $j>
, чтобы найти символ в конце слова. Я пробовал использовать grep -E $j>
и grep '$j>'
, но ни то, ни другое не сработало.
Вторая проблема заключается в том, что я не знаю, как вывести название языка (в переменной lang
). Вложение другого for
цикла не сработало, когда я попробовал это так (или с i и k в обратном порядке):
(
for i in $count
do
for k in $lang
do
for j in {a..z}
do
echo -e $k $j $(grep -c $j> $i)
done
) | sort -k3 -rn | head -1
done
done
) | column -t
Поскольку это выводит кратные названия языка « $k
» в местах, где ему не принадлежит.
Я знаю, что могу просто скопировать и вставить цикл для каждого языка, но я хотел бы распространить это на каждый язык. Заранее спасибо!
Комментарии:
1. Можете ли вы вставить пару строк, скажем, из двух файлов списка слов для проверки?
2. даже если бы это сработало, разве это не вывело бы неправильные числа? например, если ваш файл с подсчетом слов содержит три записи:
is 1000; xertz 1; showbiz 1;
результат был быz 2
(а неs 1000
)3. Да, Умляут, это было бы
z 2
что я и хочу, так как я хочу подсчитать частоту и отобразить символ, которым чаще всего заканчивается слово в самом файле. И, рулофс, пример файла показан здесь:de 1622928 je 1622619 est 1348809 pas 1128894 le 1093232
таким образом, в самом этом файле e чаще всего заканчивается словом. Извините за неправильное представление.
Ответ №1:
grep
границы слов
Чтобы заставить специальные разделители (например, >
для окончания слова) работать с egrep
при вызове из командной строки, вы должны поместить их в "
кавычки "
.
count=$(egrep -c "${char}>" "${file}")
Кстати, вам действительно следует использовать двойные кавычки ( "
), потому что одинарные кавычки предотвратят расширение переменной. (например, в j="foo"; k='$j>'
первый символ k
значения будет $
вместо f
)
Отображение названия языка
Получение правильной языковой строки немного сложнее; вот несколько предложений:
-
Выводите отображаемый язык из пути к списку слов:
lang=${file%/*} lang=${lang##*/}
С помощью bash (хотя и не с помощью dash и некоторых других оболочек) вы могли бы даже сделать
lang=${lang^}
заглавную строку. -
Найдите правильное название языка в словаре.
Bash-4
имеет встроенные словари, но вы также можете использовать файлы dicts:$ cat languagues.txt ./wordlist/french/fr.txt Français ./wordlist/english/en.txt English ./wordlist/german/de.txt Deutsch $ file=./wordlist/french/fr.txt $ lang=$(egrep "^${file}/>" languages.txt | awk '{print $2}')
-
Вы также можете выполнять итерации по
file,lang
парам, напримерlanguages="french/fr,French spanish/es,Español german/de,Deutsch" for l in $languages; do file=./wordlist/${l%,*}.txt lang=${l#*,} # ... done
Принимая во внимание частоты слов
Третья проблема, которую я вижу (хотя я могу неправильно понять проблему), заключается в том, что вы не принимаете во внимание частоту слов. например, слово A, которое используется в 1000 раз чаще, чем слово B, будет учитываться только один раз (точно так же, как B).
Вы можете использовать awk
для суммирования частот совпадающих слов:
count=$(egrep "${char}>" "${file}" | awk '{s =$2} END {print s}')
Теперь все вместе
Таким образом, полное решение проблемы может выглядеть как:
languages="french/fr,French spanish/es,Español german/de,Deutsch"
(
echo -e "Language Letter Count"
for l in ${languages}; do
file=./wordlist/${l%,*}.txt
lang=${l#*,}
for char in {a..z}; do
#count=$(egrep -c "${char}>" "${file}")
count=$(egrep "${char}>" "${file}" | awk '{s =$2} END {print s}')
echo ${file} ${char} ${count}
done | sort -k3 -rn | head -1
done
) | column -t
Комментарии:
1. Это сработало чудесно, и я узнал кое-что новое, спасибо Umlaute!
2. У меня есть вопрос, если вы не возражаете, можете ли вы рассказать мне, как вы использовали
${l%,*}
и${l#*,}
? Я все еще в замешательстве по поводу использования%
и#
в скрипте, что именно они означают?3. @Angelo
man bash
и search for##
должны дать вам объяснение, которое лучше всего, что я мог бы сказать.