3

基本的に私が持っているのは、数字の行を含むテキストファイル(file.txt)です(行は必ずしも同じ長さではありません)。


1 2 3 4
5 6 7 8
9 10 11 12 13

私がする必要があるのは、これらの番号を一度に 1 つずつ削除して新しいファイルを書き込み、置換を行うことです。たとえば、最初の新しいファイルには次のものが含まれます。


2 3 4 <--- 最初の要素を削除
5 6 7 8
9 10 11 12 13

7番目のファイルには次が含まれます


1 2 3 4
5 6 8 <--- ここで 7 番目の要素を削除
9 10 11 12 13

これらを生成するために、各行をループしてから、各行の各要素をループしています。たとえば、2 行目の 3 番目の要素を削除する 7 番目のファイルの場合、行を読み込んで適切な要素を削除し、この新しい行を再挿入することでこれを実行しようとしています。


$lineNo は 2 (2 行目)
$line は 5 6 7 8
を切り取り、3 番目の数字を削除して $newline 5 6 8 にします

次に、sed を使用して file.txt の $lineNo 行を $newline に置き換えようとします:
sed -n '$lineNo s/.*/'$newline'/' > file.txt

これはまったく機能していません。
sed: can't read 25.780000: No such file or directory (25.780000 はテキスト ファイル内の数字です。ファイルなどを読み取るために

$newline を使用しようとしているようです) というエラー が表示されます。
どの行を置き換えるかを指定しても機能しません:(

私の質問は、a) sed ではなくこれを行うためのより良い方法はありますか、b) sed が進むべき道である場合、私は何を間違っていますか?

ありがとう!!

4

4 に答える 4

3

ファイルが大きい場合はかなり遅くなりますが、質問を誤解していない限り、次のように動作するはずです。

#! /bin/bash

remove_by_value()
{
  local TO_REMOVE=$1

  while read line; do 
    out=
    for word in $line; do [ "$word" = "$TO_REMOVE" ] || out="$out $word"; done
    echo "${out/ }"
  done < $2
}

remove_by_position()
{
  local NTH=$1

  while read line; do
    out=
    for word in $line; do
      ((--NTH == 0)) || out="$out $word"
    done
    echo "${out/ }"
  done < $2
}

FILE=$1
shift  
for number; do
  echo "Removing $number"
  remove_by_position $number "$FILE"
done

これにより、すべての出力が stdout にダンプされますが、削除された各数値の出力がリダイレクトされるように変更するのは簡単なはずです (たとえばremove_by_position $number $FILE > $FILE.$$ && mv $FILE.$$ $FILE.$number、適切な引用符を使用して)。次のように実行します。

$ bash script.sh file.txt $(seq 11)
于 2012-04-17T20:59:26.903 に答える
3
filename=file.txt
i=1
while [[ -s $filename ]]; do
    new=file_$i.txt
    awk 'NR==1 {if (NF==1) next; else sub(/^[^ ]+ /, "")} 1' $filename > $new
    ((i++))
    filename=$new
done

これにより、新しいファイルごとに最初の行の先頭にスペースが残り、行が空になるとその行は削除されます。最後に生成されたファイルが空になると、ループは終了します。


要件の明確化による更新:

words=$(wc -w < file.txt)
for ((i=1; i<=words; i++)); do 
    awk -v n=$i '
        words < n && n <= words+NF {$(n-words) = "" }
        {words += NF; print}
    ' file.txt > file_$i.txt
done
于 2012-04-17T20:17:58.507 に答える
1

認めざるを得ないのは、他のソリューションの短さに少し驚いたことです。

#!/bin/bash
#
file=$1
lines=$(cat $file | wc -l) 
out=0

dropFromLine () {
    file=$1
    row=$2
    to=$((row-1))
    from=$((row+1))
    linecontent=($(sed -n "${row}p" $file))
    # echo "    linecontent: " ${linecontent[@]}
    linelen=${#linecontent[@]}
    # echo "    linelength: " $linelen
    for n in $(seq 0 $linelen) 
    do
        ( 
        if [[ $row > 1 ]] ; then sed -n "1,${to}p" $file ;fi
        for i in $(seq 0 $linelen) 
        do
            if [[ $n != $i ]]
            then
                echo -n ${linecontent[$i]}" " 
            fi
        done
        echo 
        # echo "mod - drop " ${linecontent[$n]}
        sed -n "$from,${lines}p" $file 
        ) > outfile-${out}.txt
        out=$((out+1))
    done 
}

for row in $(seq 1 $lines)
do 
    dropFromLine $file $row 
done

呼び出し:

./dropFromRow.sh num.dat

数値:

1 2 3 4
5 6 7 8
9 10 11

結果:

outfile-0  outfile-10  outfile-12  outfile-2  outfile-4  outfile-6  outfile-8
outfile-1  outfile-11  outfile-13  outfile-3  outfile-5  outfile-7  outfile-9

サンプル:

asux:~/proj/mini/forum > cat outfile-0
2 3 4  
5 6 7 8
9 10 11
asux:~/proj/mini/forum > cat outfile-1
1 3 4  
5 6 7 8
9 10 11
于 2012-04-17T21:49:35.647 に答える
0

を使用した片道perl

の内容file.txt:

1 2 3 4
5 6 7 8
9 10 11 12 13

の内容script.pl:

use warnings;
use strict;

## Read all input to a scalar variable as a single string.
my $str;
{
        local $/ = undef;
        $str = <>;
}

## Loop for each number found.
while ( $str =~ m/(\d+)(?:\h*)?/g ) {

        ## Open file for writing. The name of the file will be
        ## the number matched in previous regexp.
        open my $fh, q[>], ($1 . q[.txt]) or
                die qq[Couldn't create file $1.txt\n];

        ## Print everything prior to matched string plus everything
        ## after matched string.
        printf $fh qq[%s%s], $`, $';

        ## Close file.
        close $fh;
}

次のように実行します。

perl script.pl file.txt

作成されたファイルを表示:

ls [0-9]*.txt

出力あり:

10.txt  11.txt  12.txt  13.txt  1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt

それらのいずれかのコンテンツを表示します。

cat 9.txt

出力:

1 2 3 4
5 6 7 8
10 11 12 13
于 2012-04-21T22:42:33.740 に答える