web-dev-qa-db-ja.com

より良い貼り付けコマンド

私は次の2つのファイルを持っています(ファイルのすべての行が同じ幅になるように行にドットを埋め込み、file1をすべて大文字にしてより明確にしました)。

contents of file1:

ETIAM......
SED........
MAECENAS...
DONEC......
SUSPENDISSE

contents of file2

Lorem....
Proin....
Nunc.....
Quisque..
Aenean...
Nam......
Vivamus..
Curabitur
Nullam...

File2がfile1より長いことに注意してください。

このコマンドを実行すると:

paste file1 file2

私はこの出力を取得します

ETIAM...... Lorem....
SED........ Proin....
MAECENAS... Nunc.....
DONEC...... Quisque..
SUSPENDISSE Aenean...
    Nam......
    Vivamus..
    Curabitur
    Nullam...

出力を次のようにするにはどうすればよいですか?

ETIAM...... Lorem....
SED........ Proin....
MAECENAS... Nunc.....
DONEC...... Quisque..
SUSPENDISSE Aenean...
            Nam......
            Vivamus..
            Curabitur
            Nullam...

私は試した

paste file1 file2 | column -t

しかし、それはこれを行います:

ETIAM......  Lorem....
SED........  Proin....
MAECENAS...  Nunc.....
DONEC......  Quisque..
SUSPENDISSE  Aenean...
Nam......
Vivamus..
Curabitur
Nullam...

元の出力ほど醜くないが、とにかく列ごとに間違っている。

11

ファイルにタブ文字がない場合は、

paste file1 file2 | expand -t 13

引数は-t file1の必要な最大行幅をカバーするように適切に選択されています。

OPはより柔軟なソリューションを追加しました:

私はこれを行ったので、マジックナンバー13なしで機能します:

paste file1 file2 | expand -t $(( $(wc -L <file1) + 2 ))

入力は簡単ではありませんが、スクリプトで使用できます。

17
Mark Plotnick

Awkがうまくできると思ったので、「2つのファイルから入力を読み取るawk」をグーグル検索して、出発点として使用する stackoverflowに関する記事 を見つけました。

最初は要約バージョンで、次にその下で完全にコメントされています。これが完了するまでに数分以上かかりました。賢い人たちからのいくつかの改良をうれしく思います。

awk '{if(length($0)>max)max=length($0)}
FNR==NR{s1[FNR]=$0;next}{s2[FNR]=$0}
END { format = "%-" max "s\t%-" max "s\n";
  numlines=(NR-FNR)>FNR?NR-FNR:FNR;
  for (i=1; i<=numlines; i++) { printf format, s1[i]?s1[i]:"", s2[i]?s2[i]:"" }
}' file1 file2

そして、これは上記の完全に文書化されたバージョンです。

# 2013-11-05 [email protected]
# Invoke thus:
#   awk -f this_file file1 file2
# The result is what you asked for and the columns will be
# determined by input file order.
#----------------------------------------------------------
# No matter which file we're reading,
# keep track of max line length for use
# in the printf format.
#
{ if ( length($0) > max ) max=length($0) }

# FNR is record number in current file
# NR is record number over all
# while they are equal, we're reading the first file
#   and we load the strings into array "s1"
#   and then go to the "next" line in the file we're reading.
FNR==NR { s1[FNR]=$0; next }

# and when they aren't, we're reading the
#   second file and we put the strings into
#   array s2
{s2[FNR]=$0}

# At the end, after all lines from both files have
# been read,
END {
  # use the max line length to create a printf format
  # the right widths
  format = "%-" max "s\t%-" max "s\n"
  # and figure the number of array elements we need
  # to cycle through in a for loop.
  numlines=(NR-FNR)>FNR?NR-FNR:FNR;
  for (i=1; i<=numlines; i++) {
     printf format, s1[i]?s1[i]:"", s2[i]?s2[i]:""
  }
}
4
Mike Diehn

Debianとその派生物では、columnには_-n_ nomergeオプションがあり、列が空のフィールドで正しいことを行うことができます。内部的には、columnwcstok(wcs, delim, ptr)関数を使用します。この関数は、ワイド文字列を、delim引数のワイド文字で区切られたトークンに分割します。

wcstokは、トークンを認識する前に、delimのワイド文字をスキップすることから始まります。 _-n_オプションは、delimの最初のワイド文字をスキップしないアルゴリズムを使用します。

残念ながら、これはあまり移植性がありません。_-n_はDebian固有であり、columnはPOSIXにはありません。これは明らかにBSDのものです。

2
ninjalj

あまり良い解決策ではありませんが、私はそれを使用してそれを行うことができました

paste file1 file2 | sed 's/^TAB/&&/'

ここで、TABはタブ文字に置き換えられます。

2
unxnut

パディングに使用したドットを取り除く:

file1:

ETIAM
SED
MAECENAS
DONEC
SUSPENDISSE

file2:

Lorem
Proin
Nunc
Quisque
Aenean
Nam
Vivamus
Curabitur
Nullam

これを試して:

$ ( echo ".TS"; echo "l l."; paste file1 file2; echo ".TE" ) | tbl | nroff | more

そしてあなたは得るでしょう:

ETIAM         Lorem
SED           Proin
MAECENAS      Nunc
DONEC         Quisque
SUSPENDISSE   Aenean
              Nam
              Vivamus
              Curabitur
              Nullam
2
Jeff Taylor

かなり移植可能で、任意の数の入力ファイルに対して機能するawkソリューション:

# Invoke thus:
#   awk -F\\t -f this_file file1 file2

# every time we read a new file, FNR goes to 1

FNR==1 {
    curfile++                       # current file
}

# read all files and save all the info we'll need
{
    column[curfile,FNR]=$0          # save current line
    nlines[curfile]++               # number of lines in current file
    if (length > len[curfile])
            len[curfile] = length   # max line length in current file
}

# finally, show the lines from all files side by side, as a table
END {
    # iterate through lines until there are no more lines in any file
    for (line = 1; !end; line++) {
            $0 = _
            end = 1

            # iterate through all files, we cannot use
            #   for (file in nlines) because arrays are unordered
            for (file=1; file <= curfile; file++) {
                    # columnate corresponding line from each file
                    $0 = $0 sprintf("%*s" FS, len[file], column[file,line])
                    # at least some file had a corresponding line
                    if (nlines[file] >= line)
                            end = 0
            }

            # don't print a trailing empty line
            if (!end)
                    print
    }
}
1
ninjalj