単語に基づいてファイルを2つのファイルに分割する

単語に基づいてファイルを2つのファイルに分割する

male_nominee.txtfemale_nominee.txt性別に応じて、次のファイルを2つのファイルに分割するシェルスクリプトを作成します。ファイルが 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私の出力には両方のファイルの内容があります。誰でもこの問題を解決するのに役立ちますか?

答え1

また、いくつかの変更があります。

awk — シングルパス

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

〜のようにjesse_bの答えただし、ファイルを一度だけ読み込み、awkスクリプト内でI / Oリダイレクトを実行します。これらの awk 回答を使用すると、データ型を変更できます。

年齢|名前|性別|高い|重量|…

|しかし、彼らは2番目と性別の間にスペースがある線を無視します。

強く打つ

#!/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

私はこれがあなたが望むものだと思います。各行をシェルで読み、性別が男性か女性かをテストします。

  • 一般的にJesseの言葉は正しいです。通常これを避けるべきです  while read。バラよりシェルループを使用してテキストを処理するのはなぜ悪い習慣と見なされますか?  ただし、シェルループを使用してテキストを処理することの欠点の1つは、ループが繰り返されるたびに外部ユーティリティを呼び出すことが多いことです。この例ではそうではありません。
  • また、人為的に何かをするように指定された場合殻に完全に入っていて、 その後、宿題の規則に従う必要があります。
  • これはファイルのスペースにもっと寛大ですが、セックスの後に追加データを許可しません。
  • Bashは=~文字列を正規表現と比較します。正規表現では$終了を意味しますので、$line =~ Male$ 以下を確認してください。$line によって。 。終わる Male$line =~ Male(を連れてこないで) ただ言うと$マレピセントラという女性は男と見なされます。
  • \データのバックスラッシュ()が気になるならread -rread
  • この場合、それは重要ではないかもしれませんが(すべての行が数字で始まる場合)、通常printfecho

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(none)を選択すると、その*項目のみが一致します。ただ言葉Male (つまり、年齢と名前なし)。一方、これは最後にマークアップを追加する必要がないことを意味します。

答え2

「Fmale_nominee.txt と male_nominee.txt の内容を表示する」要件は少し不明瞭で、IMO はスクリプトには存在しませんが、とにかく含めます。ファイルを読むために通常while readループを使用することは避けなければなりません。これは区切りファイルであるため、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

また、スクリプトにはいくつかの問題があります。

ファイルに両方の条件が含まれており、両方の条件が毎回通過するため、あなたのステートメントは代わりにifgrepです。names.txtlineMaleFemale

すべての行で変数に割り当てる必要はなく、変数は使用されません。あなたはこれを行うことができますif echo "$line" | grep -q 'Male'; then

if / elseのように、2つのifステートメントは必要ありません。

if echo "$line" | grep -q 'Male'; then
  echo "$line" >>male_nominee.txt
else
  echo "$line" >>female_nominee.txt
fi

答え3

あなたの質問は声明です

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

する:

  1. 「男性」の全検索names.txt
  2. 出力(「男性を含むすべての行」)を返し、それを変数に割り当てます。i
  3. もし分配する成功した場合(常に成功する必要がある場合)、ifの内容を実行します。

1行ずつ読みながら、その行だけを確認したい場合があります。

使用できますif echo "$line" | grep -q "Male"(またはPOSIXで定義されていない-qを回避するには、出力にリダイレクトされます/dev/null)。

これは行全体で「Male」を検索するため、ファイルに「AMalek」という人が含まれていると失敗する可能性があります。

読み込むのではなく、1行ずつ読み込むときは、IFS="|" read -r age name gender次のものを使用できます。if [ $var = "value" ];

別のオプションはgrepを使用することです。この場合、先行する"|"(特殊文字であることに注意)が必要であり、行が終了します。

この場合、ループ全体をいくつかのgrepに置き換えることができます。

(女性のミスは男のミスと同じです)

答え4

以下は簡単な解決策です。 grepでフィルタリングし、">>"を使って追加します。

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

cat female_nominee.txt
cat male_nominee.txt

関連情報