2016-07-30 3 views
-1

Мой вопрос не так просто спросить, я пытаюсь объяснить проблему следующим примером:Counting результат Grep не будет работать в Баш скрипт

/home/luther/tipical_surnames.txt

Smith 
Johnson 
Williams 
Jones 
Brown 
#Davis 
Miller 
Wilson 
#Moore 
Taylor 
Anderson 

/дома /luther/employers.txt

2000 Johnson  A lot-of details/BJC3000,6000, i550    0 
2101 Smith  A lot-of details/BJC3000,6000, i550    0 
2102 Smith  A lot-of details/BJC3000,6000, i550    0 
2103 Jones  A lot-of details/BJC3000,6000, i550    0 
2104 Johnson  A lot-of details/BJC3000,6000, i550    0 
2100 Smith  A lot-of details/BJC3000,6000, i550    0 

у меня есть список с любимыми фамилиями и другим с именем работодателей. Давайте посмотрим, сколько людей имеют самую популярную фамилию в компании, с помощью консоли:

grep -v "#" /home/luther/tipical_surnames.txt | sed -n 1'p' | cut -f 1 
Smith 
grep Smith /home/luther/employers.txt | wc -l 
230 

отработаны. Теперь давайте проверить первые 5 самых популярных фамилий с помощью простой Баш скрипт:

#!/bin/bash 
counter=1 
while [ $counter -le 5 ] 
do 
    surname=`grep -v "#" /home/luther/tipical_surnames.txt | sed -n "$counter"'p' | cut -f 1` 
    qty=`grep "$surname" /home/luther/employers.txt | wc -l` 
    echo $surname 
    echo $qty 
    counter=$(($counter + 1)) 
done 

И результат в следующем:

Smith 
0 
Johnson 
0 
Williams 
0 
Jones 
0 
Brown 
0 

Что не так?

Обновление: Как я уже писал, я тестировал скрипт на другом компьютере, и все работает нормально. После я стараюсь следовать:

[email protected]:/var/www# cat testfile.bash 
#!/bin/bash 
for ((c=1; c<=5; c++)) 
{ 
echo $c 
} 

[email protected]:/var/www# bash testfile.bash 
testfile.bash: line 2: syntax error near unexpected token `$'\r'' 
'estfile.bash: line 2: `for ((c=1; c<=5; c++)) 
[email protected]:/var/www# echo $BASH_VERSION 
4.2.37(1)-release 
[email protected]:/var/www# 

Конечно, на другом компьютере, это просто сценарий работы, как и ожидалось, без ошибок.

+0

Оболочка - это среда, из которой можно вызвать инструменты, а не инструмент для манипулирования текстом. Стандартный, универсальный UNIX-инструмент для управления текстом - awk. Вы боретесь, потому что используете неправильный инструмент, и это было бы чрезвычайно сложно и неэффективно для того, чтобы делать то, что вы хотите надежно в оболочке (см. [Why-is-use-a-shell-loop-to-process-text- считается, плохая практика] (http://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice)). Бросьте его и начинайте с awk. Опубликуйте краткий, проверяемый ввод проб и ожидаемый результат, и мы можем вам помочь. –

+0

Я думаю, у вас есть файл с терминаторами линии DOS. Вы не видите их при копировании/вставке программы, но они будут присутствовать в захваченной переменной и не позволят окончательному 'grep' что-либо совместить. Попробуйте 'dos2unix' в файлах. Для дальнейшего устранения неполадок в [Stack Overflow 'bash' tag wiki] (// stackoverflow.com/tags/bash/info) содержится подробный раздел об этой проблеме. – tripleee

+0

@ Ed Morton Хорошо, это ясно, но я до сих пор не понимаю, почему мой код будет хорошим, если я заменил переменную $ surname на значение. Как видно из результата, переменная $ surname имеет хорошее значение, когда я хочу распечатать ее на экране. Почему одна и та же переменная не работает, когда я использую объявление переменной $ qty? – Luther

ответ

0

Я на самом деле не совсем уверен. Я протестировал ваш скрипт, скопировав его и вставив в него, с воображаемыми данными (/usr/share/dict/words) и, похоже, работает так, как ожидалось. Интересно, есть ли разница между сценарием, который вы опубликовали, и скриптом, который вы используете?

Несмотря на то, что я взял на себя смелость сделать его немного более плавным. Обратите внимание, как в цикле вы читаете всю полноту файла фамилий на каждой итерации? Кроме того, grep + wc -l может быть заменен на grep -c. Я также добавляю -F к первому вызову grep, так как шаблон (#) является фиксированной строкой. grep в файл сотрудника использует \<$name\>, чтобы убедиться, что мы получаем только Johns and no Johnssons, когда $name - John.

#!/bin/bash 

employees_in="/usr/share/dict/words" 
names_in="/usr/share/dict/words" 

grep -v -F "#" "$names_in" | head -n 5 | cut -f 1 | 
while read -r name; do 
    count="$(grep -c "\<$names\> " "$employees_in")" 
    printf "name: %-10s\tcount: %d\n" "$name" "$count" 
done 

тестирования:

$ bash script.sh 
name: A    count: 1 
name: a    count: 1 
name: aa   count: 1 
name: aal   count: 1 
name: aalii   count: 1 

Примечание: Я получаю только те, в подсчете, так как словарь (не удивительно) содержит только уникальные слова.

+0

Спасибо, ответ и ваше решение. Нет разницы между вставленными кодами. Я попробовал его с другим компьютером и сгенерированными исходными файлами, и он действительно работает нормально. Проблема может быть в исходных файлах. – Luther

+0

@Luther Да, если файл сотрудника пуст или просто не содержит имен, считанных из файла фамилий (это было бы легко проверить). У меня создалось впечатление, что вы запустили свой первый пример командной строки и скрипт на том же компьютере. – Kusalananda

+0

Это не удастся, когда он сопоставит Джона с Джонстоном, Смитом с Смитерсом и т. Д., И когда он соответствует сотруднику Johnston с названием компании Johnston & Johnston и т. Д. –

2

Это, очевидно, непроверенное, так как вы не отправили ввод образца, но это такой подход следует использовать:

awk ' 
NR==FNR { if (!/#/) cnt[$1]=0; next } 
{ cnt[$WHATEVER]++ } 
END { 
    PROCINFO["sorted_in"] = "@val_num_desc" 
    for (name in cnt) { 
     print name, cnt 
     if (++c == 5) { 
      break 
     } 
    } 
} 
' /home/luther/tipical_surnames.txt /home/luther/employers.txt 

Заменить «WHATEVER» с номером поля, где фамилии сотрудника хранятся в работодателях. текст.

выше использует GNU AWK для sorted_in с другим awks я бы просто удалить PROCINFO линию и отсчет от выходного контура и трубы вывода для сортировки затем голова, например:

awk ' 
NR==FNR { if (!/#/) cnt[$1]=0; next } 
{ cnt[$WHATEVER]++ } 
END { 
    for (name in cnt) { 
     print name, cnt 
    } 
} 
' /home/luther/tipical_surnames.txt /home/luther/employers.txt | sort -k2,1nr | head -5 

или что-то правильные параметры сортировки.

+0

Спасибо за ваше решение, его внешний вид очень полезен! Но я до сих пор не знаю, почему мой код не работает. – Luther

+0

Снова, скрипты оболочки для обработки текста являются хрупкими и трудными для написания достоверно/правильно.Есть так много вещей, которые могут вызвать проблему, и трудно догадаться, что это на самом деле делает. Я вижу, что вы используете 'cut -f 1' в конце строки' surname = ... ', которая ничего не сделает абсолютно с файлом, который вы опубликовали, - как вы думаете, что он будет делать? В файле, который вы разместили, есть только 1 поле, так почему вы, по-видимому, пытаетесь выбрать 1 поле, когда все это есть в файле? –

Смежные вопросы