Как перебирать слова моего текстового документа в оболочке. я хочу отобразить количество слов в моем текстовом документе

Я пробовал это, но вместо этого он показывает количество строк.

declare -i x=0 while IFS="" read -r p || [ -n "$p" ] do x=x+1 done <test.txt echo "$x

Буду признателен, если кто-нибудь сможет это объяснить, так как я новичок

wc -w test.txt?
tkausl 10.09.2018 08:39

Привет @tkausl. Это работает. Большое вам спасибо. Но я хочу повторить слова. Не только количество слов. заранее спасибо

Chitti_the_robot 10.09.2018 08:42

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

James Brown 10.09.2018 08:59
for i in $(cat file); do something $i; done вместо использования чтения и перенаправления, вероятно, является самым простым решением
Sam 10.09.2018 09:17

@Sam for i in $(cat file) - известный анти-паттерн. Всегда есть лучшее решение, чем это.

Ed Morton 11.09.2018 16:30

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

Sam 11.09.2018 16:48

@Sam, если он содержит *, вы получите список повторяющихся имен файлов. Зачем вам вообще его использовать, если есть альтернативы, у которых нет побочных эффектов и ошибок? while read -r -a words; do for word in "${words[@]}"; do ...; done; done <test.txt

Charles Duffy 11.09.2018 17:54

у вас есть смысл в том, что с моей стороны было безрассудно предлагать без напоминания переключать глобус с помощью set -f / set +f, если есть малейшая вероятность, что файл может содержать какие-либо специальные символы.

Sam 11.09.2018 19:00

Однако обратите внимание, что set -f; for i in $(cat file); do echo $i >/dev/null; done; set +f примерно в два раза быстрее, чем эквивалентный while read -r -d' ' i; do echo $i >/dev/null; done для большого файла в моей системе, и что решение с массивом может дать сбой для очень длинных строк.

Sam 11.09.2018 19:10
2
9
65
3

Ответы 3

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

echo $'word1 word2! word3
\tword4\t\t\t\t\t\tword5\tword6
word7 word8


word9 word10' | \
while IFS=$'\t ' read -ra linewords; do
    for i in "${linewords[@]}"; do
            echo word is "'$i'"
    done
done

выведет:

word is 'word1'
word is 'word2!'
word is 'word3'
word is 'word4'
word is 'word5'
word is 'word6'
word is 'word7'
word is 'word8'
word is 'word9'
word is 'word10'

Он использует несколько значений IFS в сочетании с чтением read в массив, см. этот ответ о том, как разделить строку по разделителю.

Вы выбрали удобный вход, для которого работает ваш код :) Попробуйте использовать табуляцию между word5 и word6 вместо пробела. Проблема в том, что вы хотите использовать $'...' вместо $"...". См. руководство по эксплуатации для объяснения $"...". Кроме того, поскольку read по умолчанию считывает строки, в \n нет необходимости.

PesaThe 10.09.2018 11:24

Я бы использовал для этого awk:

$ echo "Lorem ipsum dolor sit amet,
        consectetur adipisci elit,
        ..." | 
awk '{
    for(i=1;i<=NF;i++)
        print "iterating " $i
}'

Выход:

iterating Lorem
iterating ipsum
iterating dolor
iterating sit
iterating amet,
iterating consectetur
iterating adipisci
iterating elit,
iterating ...
grep -oE '\w+' YOUR_FILE.txt

записывает слова из YOUR_FILE.txt в стандартный вывод. Вставьте это в свой цикл, и у вас будет итерация по словам.

Это предполагает, что «слово» в вашем случае - это один или несколько символов, описанных \w, то есть либо подчеркивание, либо то, что ваша текущая локаль определяет как буквенно-цифровой символ. Если ваше представление о «слове» отличается, вы, конечно, можете адаптировать регулярное выражение в соответствии со своими потребностями.

Другие вопросы по теме