Напишите сценарий оболочки, чтобы разделить приведенный ниже файл на два файла. male_nominee.txt и female_nominee.txt в зависимости от пола. Если файл male_nominee.txt или female_nominee.txt уже существует, затем добавьте контент.

Показать содержимое female_nominee.txt и male_nominee.txt

names.txt

23|Arjun|Male

24|Akshara|Female

17|Aman|Male

19|Simran|Female

Мой код:

while IFS= read -r line;
do
    if i=$(grep "Male" names.txt)
    then
        echo "$line" >> male_nominee.txt
    fi
    if j=$(grep "Female" names.txt)
    then
        echo "$line" >> female_nominee.txt
    fi
done < "names.txt"
ls
cat male_nominee.txt
cat female_nominee.txt

В моем выводе у меня есть содержимое names.txt в обоих моих файлах. Может ли кто-нибудь помочь мне с этой проблемой?

2
Greenonline 21 Авг 2020 в 10:06
В классах обычно бывают довольно ужасные задания, но это одно из худших, что я видел.
 – 
jesse_b
20 Авг 2020 в 21:37

5 ответов

Лучший ответ

Еще несколько вариаций:

Awk — одиночный проход

awk -F'|' '
   $3 == "Male"   { print >> "male_nominee.txt"   }
   $3 == "Female" { print >> "female_nominee.txt" }
          ' names.txt

Аналогичен ответу jesse_b, но читает файл только один раз и выполняет перенаправление ввода-вывода в сценарии awk. Обратите внимание, что эти ответы awk позволяют изменять формат данных; например.,

age|name|sex|height|weight|…

Но они будут игнорировать строку, где есть пробел между вторым | и полом.

Трепать

#!/bin/bash
while read line
do
        if [[ $line =~ Male$ ]]
        then
                printf '%s\n' "$line" >> male_nominee.txt
        fi
        if [[ $line =~ Female$ ]]
        then
                printf '%s\n' "$line" >> female_nominee.txt
        fi
done < names.txt

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

  • Джесси прав, в целом: Как правило, следует избегать чтения файлов с циклом while read. См. Почему использование цикла оболочки для обработки текста считается плохой практикой? Но один из недостатков использования цикла оболочки для обработки текста заключается в том, что люди часто вызывают внешнюю утилиту на каждой итерации цикла, и этот пример не делает этого.
  • Кроме того, если вам дали искусственное задание сделать что-то полностью в оболочке то следует следовать правилам задания.
  • Это более терпимо к пробелам в файле, но не допускает дополнительных данных после секса.
  • В bash =~ сравнивает строку с регулярным выражением. В регулярном выражении $ означает конец, поэтому $line =~ Male$ проверяет, заканчивается ли $line на Male. Если мы просто сказали $line =~ Male (без $), тогда женщина по имени Малефисента будет считаться мужчиной.
  • Если вас беспокоят обратные косые черты (\) в данных, используйте read -r вместо просто read.
  • Наверное, в данном случае это не имеет значения (если каждая строка начинается с цифры), но в целом printf безопаснее, чем echo.

POSIX-оболочка

#!/bin/sh
while read line
do
        case "$line" in
            (*Male)
                printf '%s\n' "$line" >> male_nominee.txt
                ;;
            (*Female)
                printf '%s\n' "$line" >> female_nominee.txt
                ;;
        esac
done < names.txt
  • Это будет более портативно, чем версия bash.
  • case – традиционный способ проверки строки на соответствие шаблону(ам) в оболочке. Он использует шаблоны сопоставления имен файлов (т. е. glob). вместо регулярных выражений.
  • Шаблон шара должен совпадать, поэтому нам нужно поставить * перед значениями пола. Если мы проверили Male (без *), он будет соответствовать только строкам, которые содержат только слово Male (т. е. без возраста и имени). С другой стороны, это означает, что нам не нужно ставить маркер на конце.
1
G-Man Says 'Reinstate Monica' 23 Авг 2020 в 02:11

Требование «Отображать содержимое female_nominee.txt и male_nominee.txt» неясно, и IMO не имеет места в сценарии, но я все равно включил его. Как правило, вам следует избегать чтения файлов с циклом чтения while, и, поскольку это файл с разделителями, им легко управлять с помощью awk:

#!/usr/bin/env sh 

infile=./names.txt

awk -F\| '$3 == "Male"' "$infile" >> male_nominee.txt
awk -F\| '$3 == "Female"' "$infile" >> female_nominee.txt

cat male_nominee.txt female_nominee.txt

Кроме того, некоторые проблемы с вашим скриптом:

Ваши операторы if выбираются из names.txt вместо line, поскольку этот файл содержит как Male, так и Female, и оба условия будут выполняться каждый раз.

Нет необходимости назначать переменную в каждой строке, эта переменная никогда не используется. Вы можете просто сделать if echo "$line" | grep -q 'Male'; then

Вам не нужны два оператора if, так как это будет if/else

if echo "$line" | grep -q 'Male'; then
  echo "$line" >>male_nominee.txt
else
  echo "$line" >>female_nominee.txt
fi
1
jesse_b 20 Авг 2020 в 21:49

Ваша проблема в том, что заявление

if i=$(grep "Male" names.txt)

Воля:

  1. Искать "мужской" во всем names.txt
  2. Верните вывод («все строки, содержащие Male»), назначив его переменной i
  3. Если назначение было успешным (должно быть всегда), выполните содержимое if

Поскольку вы читаете строку за строкой, вы, вероятно, захотите проверить только эту строку.

Вы можете сделать это с помощью if echo "$line" | grep -q "Male" (или, если вы хотите избежать -q, который не определен в POSIX, перенаправьте вывод на /dev/null)

Обратите внимание, что это будет искать «мужской» во всей строке, поэтому может произойти сбой, если, например. в вашем деле был кто-то по имени "Амалек".

Поскольку вы читаете строку за строкой, а не читаете, вы можете использовать IFS="|" read -r age name gender, а затем просто if [ $var = "value" ];

Другой вариант, использующий grep, - потребовать начального "|" (обратите внимание, что это специальный символ) и что он завершает строку.

Обратите внимание, что в таком случае вы можете заменить весь цикл парой greps.

(ошибка с самками точно такая же, как и с самцами)

0
Ángel 20 Авг 2020 в 21:44
#!/bin/sh

 grep  "male$" names.txt | cat >> female_nominee.txt

 cat female_nominee.txt

 grep "Male" names.txt | cat >> male_nominee.txt

 cat male_nominee.txt
0
Kevdog777 21 Авг 2020 в 10:42
1
Добро пожаловать на сайт, и спасибо за ваш вклад. Не могли бы вы объяснить, что делает этот скрипт и как? Зачем вам нужно направлять вывод grep в cat и перенаправлять это в файлы вместо прямого перенаправления вывода grep?
 – 
AdminBee
21 Авг 2020 в 11:07

Вот простое решение с использованием grep для фильтрации и ">>" для добавления.

grep "Female$" names.txt >> female_nominee.txt
grep "Male$" names.txt >> male_nominee.txt

cat female_nominee.txt
cat male_nominee.txt
0
Shield77 26 Авг 2021 в 12:44