0

私は Linux bash 環境で作業しており、編集するファイルが 900 ほどあります。1 つのファイル filename.txt には、1 行に 1 つのファイル名のファイル名のリストがあります。例えば

ab2.pdb.101
ab2.pdb.109
ab2.pdb.126
ab2.pdb.127
ab2.pdb.13
ab2.pdb.187
ab2.pdb.188

これらのファイルのコンテキストの最初の数行は次のようになります (合計 245 行)

REMARK   1                     PDB file generated by ptraj (set    33)
ATOM      1  N   ALA     1      11.304   3.018  20.878  0.1414  1.8240
ATOM      2  H1  ALA     1      11.574   3.686  21.593  0.1997  0.6000
ATOM      3  H2  ALA     1      11.901   3.162  20.074  0.1997  0.6000
ATOM      4  H3  ALA     1      10.342   3.207  20.625  0.1997  0.6000
ATOM      5  CA  ALA     1      11.449   1.637  21.381  0.0962  1.9080
ATOM      6  HA  ALA     1      12.509   1.464  21.561  0.0889  1.1000

2行目からファイルの最後までの数値の最後の2列を 0.0000 0.0000 に置き換えたい

0.1414  1.8240
0.1997  0.6000
0.1997  0.6000
0.1997  0.6000
0.0962  1.9080
0.0889  1.1000

0.0000  0.0000
0.0000  0.0000
0.0000  0.0000
0.0000  0.0000
0.0000  0.0000
0.0000  0.0000

したがって、ファイル名が「filenames.txt」という名前の 1 つのテキスト ファイルにあるファイルを読み取り、最後の 2 つの列番号を 0.0000 に置き換えたいと思います。

助けてくれてありがとう。

4

4 に答える 4

0

誰もが自分の選んだ言語で解決策を持っているのはおかしいです。個人的にはPerlも使用しますが、このミックスにさらにいくつか追加します。sedを使用したbashはどうですか?

#!/bin/bash
function fixfile() {
  #skip the 'REMARK' line and any blank lines, replace other lines
  sed '/^REMARK.*/d' $1 | sed '/^ *$/d' | sed 's/^.*/0.0000  0.0000/' > $1$$
  mv $1$$ $1
}

for fname in `cat filelist`; do
  fixfile $fname
done

「最後の2つの列番号を0.0000に置き換える」と言いましたが、この例では、これらの行が固定の「0.00000.0000」に完全に置き換えられています。行を保持して最後の2列を置き換えるつもりでしたか、それとも実際に行全体を置き換えたいのでしょうか。

于 2012-06-11T22:29:43.313 に答える
0

このコードはhead、最初の行tailを取得し、残りを取得しcut、最初の列のみを取得し、追加のpaste列を追加し (これら 2 つは列を区切るためにタブが使用されていることを前提としています)、yes列を生成するために使用します。

#! /bin/bash
while read file ; do {
        head -n1 "$file"
        tail -n+2 "$file" | \
            cut -f1-8 | \
            paste - <( yes 0.0000$'\t'0.0000 | \
            head -n $(( $( wc -l < "$file")-1 ))
        )
    }  > "$file".new
done < filenames.txt

更新: ファイルの構造がより複雑な場合は、bash よりも使いやすいものを使用します。たとえば、これは Perl で行う方法です。

#!/usr/bin/perl
use warnings;
use strict;

open my $NAMES, '<', 'filenames.txt' or die $!;
for my $file (<$NAMES>) {
    chomp $file;
    open my $FILE, '<', $file or die $!;
    open my $NEW,  '>', "$file.new" or die $!;
    print {$NEW} scalar <$FILE>;               # print 1st line
    while (<$FILE>) {
        my @fields = split /(\s+)/;            # keep separators
        @fields[-4, -2] = ('0.0000') x 2;      # replace the last two non-whitespace columns
        print {$NEW} @fields;
    }
}
于 2012-06-11T21:08:06.683 に答える
0

これを試して:

#!/bin/bash
for file in $(cat filename.txt);
do
    perl -pi -e 's/\d+(\.\d+)?(\s+)\d+(\.\d+)?$/0.0000${2}0.0000/g' $file
done

正規表現の説明:

  • $at the end は、行末に一致することを意味します
  • \d+(\.\d+)?オプションの小数部分を使用して、数値に一致することを意味します
  • (\s+)空白を「コピー」するために使用されるため、置換で保持されます

「純粋な」Bash ではないことはわかっていますが、Perl への 1 回の呼び出しが受け入れられることを願っています。

于 2012-06-11T21:54:50.710 に答える
0

列の間にタブを指定するより良い方法があると確信していますが、それは私には思い浮かびません:

#!/bin/bash

# create a list of the files to edit
declare -a FILES=(
    ab2.pdb.101
    ab2.pdb.109
    ab2.pdb.126
    ab2.pdb.127
    ab2.pdb.13
    ab2.pdb.187
    ab2.pdb.188
)

# iterate over the list
for FILE in ${FILES[@]};
do
    NEW=$FILE.new
    head -1 $FILE > $NEW
    cat $FILE | awk 'NR>1 { print $1,"\t",$2,"\t",$3,"\t",$4,"\t",$5,"\t",$6,"\t","0.000","\t","0.000" }' >> $FILE.new
done

お役に立てれば。

実際...ファイルの最初の行も保持したいかどうかはわかりません。その場合はお知らせください。これを修正します。

編集済み

各ファイルのヘッダー行を含めるように更新しました:)

于 2012-06-11T21:43:25.203 に答える