私は次の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...
元の出力ほど醜くないが、とにかく列ごとに間違っている。
ファイルにタブ文字がない場合は、
paste file1 file2 | expand -t 13
引数は-t
file1の必要な最大行幅をカバーするように適切に選択されています。
OPはより柔軟なソリューションを追加しました:
私はこれを行ったので、マジックナンバー13なしで機能します:
paste file1 file2 | expand -t $(( $(wc -L <file1) + 2 ))
入力は簡単ではありませんが、スクリプトで使用できます。
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]:""
}
}
Debianとその派生物では、column
には_-n
_ nomergeオプションがあり、列が空のフィールドで正しいことを行うことができます。内部的には、column
はwcstok(wcs, delim, ptr)
関数を使用します。この関数は、ワイド文字列を、delim
引数のワイド文字で区切られたトークンに分割します。
wcstok
は、トークンを認識する前に、delim
のワイド文字をスキップすることから始まります。 _-n
_オプションは、delim
の最初のワイド文字をスキップしないアルゴリズムを使用します。
残念ながら、これはあまり移植性がありません。_-n
_はDebian固有であり、column
はPOSIXにはありません。これは明らかにBSDのものです。
あまり良い解決策ではありませんが、私はそれを使用してそれを行うことができました
paste file1 file2 | sed 's/^TAB/&&/'
ここで、TABはタブ文字に置き換えられます。
パディングに使用したドットを取り除く:
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
かなり移植可能で、任意の数の入力ファイルに対して機能する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
}
}