長いファイルからテキスト行を抽出する

長いファイルからテキスト行を抽出する

次のテキスト ファイルがあります。

#unimportant comment
#possible more unimportant comments
#info1 info2 info3 ,importantname1
importanttext1
#info1 info2 info3 ,importantname2
importanttext2
#info1 info2 info3 ,importantname3
importanttext3

各ファイルを別々のファイルに分割したいです。必要なのは、コメントのない URL を抽出することだけです。コメントの保存はオプションです。各ファイルに、importantname1.txt のような名前を付けるか、各コメント行の末尾のカンマに続く名前に .txt を追加したものにしたいです。

したがって、importantname1.txt の内容は次のようになります。

importanttext1 

あるいはおそらく

#info1 info2 info3 ,importantname1
importanttext1

そのため、行は抽出され、コメントの後のファイル名に.txtが付加されて保存されます。この場合、ファイル名はimportantname1.txtになります。

サンプル ファイルの各行セットに対してこれを行う必要があります。コメントの保持は重要ではありませんが、スクリプト化できるようにする必要があります。また、ヘッダー内の不明な数のコメント行を考慮する必要があります。コメント行は常に、各 importanttextX 行の前にあります。

答え1

試す:

awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

サンプル入力に適用:

$ awk -F, '/^#/{f=$NF".txt";cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

上記を実行すると、ディレクトリに次のファイルが作成されます。

$ ls
file  importantname1.txt  importantname2.txt  importantname3.txt

新しいファイルの内容は次のとおりです。

$ cat importantname1.txt 
#info1 info2 info3 ,importantname1
importanttext1
$ cat importantname2.txt 
#info1 info2 info3 ,importantname2
importanttext2
$ cat importantname3.txt 
#info1 info2 info3 ,importantname3
importanttext3

使い方

awkは入力ファイルを1行ずつ読み込みます。スクリプトはそれらの行をコメントか非コメントかに分類します。コメント行の場合、ファイル名とコメントが保存されます。非コメント行の場合、新しいファイルが作成され、印刷されます。

  • `-F、

    これは、awk に入力時にフィールド区切り文字としてコンマを使用するように指示します。このようにして、ファイル名は常に最後のフィールドになります。

  • /^#/{f=$NF".txt";cmt=$0; next}

    行が で始まる場合#、最後のフィールド$NFと、.txtファイル名 を保存しますf。コメント行全体は として保存されますcmt。次に、awk に残りのコマンドをスキップして、行を最初からやり直すように指示しますnext

  • printf "%s\n%s\n",cmt,$0 >f; close(f)

    コメント行以外の行については、最後に表示されたコメントcmtと現在の行 を、$0最後に表示されたファイル名 に出力しますf。次に、 のファイル ハンドルを閉じますf

不正なファイル名からの保護

ファイル名として使用されるフィールドに が含まれている場合、OS はファイル名にディレクトリが含まれていると解釈します。これを回避するには、次のようにしてすべてを に/置き換えます。/-gsub(/\//, "-", f)

awk -F, '/^#/{f=$NF".txt";gsub(/\//, "-", f); cmt=$0; next} {printf "%s\n%s\n",cmt,$0 >f; close(f)}' file

答え2

grepとを組み合わせると、a)コメントのないすべての行とその前の info 行を ping し、b) info コメント行に基づいて出力を分割することで、csplitこの作業を実行できます。grep

grep -v -B1 '^#' file | csplit -z - '/^#/' '{*}'

-vつまり、先頭に # がある行は抽出しません^#が、そのような行の 1 行前は抽出します-B1。次に、入力されたパイプ入力を-行の先頭の各 # で分割し、空のファイルは無視して-z、できるだけ頻繁にこれを実行します{*}

名前の変更は別の手順で行う必要があります ( csplitoutpit に xx00、xx01 などの自動名前が付けられます。それぞれ、-fおよび-bオプションを使用して、接頭辞と接尾辞を変更します)

#/bin/bash
for f in xx* ; do
   mv "$f" "$( sed -n '2p' "$f" )".txt
done

関連情報