GNU/Linux >> Linux の 問題 >  >> Linux

7Linuxでの貼り付けコマンドの基本的かつ実用的な使用法

前回の記事では、CSVまたは表形式のテキストデータファイルから列を抽出するために使用できるcutコマンドについて説明しました。

paste コマンドは正反対のことを行います。いくつかの入力ファイルをマージして、それらから新しい区切りテキストファイルを生成します。 LinuxとUnixでPasteコマンドを効果的に使用する方法を見ていきます。

7Linuxでの貼り付けコマンドの実用的な例

ビデオがお好みの場合は、この記事で説明したのと同じ貼り付けコマンドの例を説明するこのビデオを見ることができます。

1。列の貼り付け

最も基本的な使用例では、paste コマンドはNを取ります 入力ファイルを出力で1行ずつ結合します:

sh$ printf "%s\n" {a..e} | tee letters
a
b
c
d
e

sh$ printf "%s\n" {1..5} | tee digits
1
2
3
4
5

sh$ paste letters digits
a    1
b    2
c    3
d    4
e    5

しかし、実際の例に取り組むために、理論的な説明を残しましょう。上のビデオで使用されているサンプルファイルをダウンロードした場合は、さまざまなに対応するいくつかのデータファイルがあることがわかります。 テーブルの:

sh$ head -3 *.csv
==> ACCOUNTLIB.csv <==
ACCOUNTLIB
TIDE SCHEDULE
VAT BS/ENC

==> ACCOUNTNUM.csv <==
ACCOUNTNUM
623477
445452

==> CREDIT.csv <==
CREDIT
<--- empty line
<--- empty line

==> DEBIT.csv <==
DEBIT
00000001615,00
00000000323,00

これらのデータからタブ区切りのテキストファイルを作成するのは非常に簡単です:

sh$ paste *.csv | head -3
ACCOUNTLIB    ACCOUNTNUM    CREDIT    DEBIT
TIDE SCHEDULE    623477        00000001615,00
VAT BS/ENC    445452        00000000323,00

ご覧のとおり、コンソールに表示された場合、そのタブ区切り値ファイルのコンテンツは完全にフォーマットされたテーブルを生成しません。ただし、これは仕様によるものです。paste コマンドは、固定幅のテキストファイルの作成には使用されませんが、フィールド区切り文字としての役割が1つの特定の文字に割り当てられている区切りテキストファイルのみに使用されます。

したがって、上記の出力で明らかでない場合でも、実際には1つだけがあります。 各フィールド間のタブ文字。 sedコマンドを使用してそれを明らかにしましょう:

sh$ paste *.csv | head -3 | sed -n l
ACCOUNTLIB\tACCOUNTNUM\tCREDIT\tDEBIT$
TIDE SCHEDULE\t623477\t\t00000001615,00$
VAT BS/ENC\t445452\t\t00000000323,00$

これで、非表示の文字が出力に明確に表示されます。そして、\tとして表示されるタブ文字を見ることができます 。それらを数えることができます。すべての出力行には常に3つのタブがあり、各フィールドの間に1つあります。そして、それらのうちの2つが連続して表示されている場合、それはそこに空のフィールドがあったことを意味するだけです。これは私の特定のサンプルファイルでよくあることです。各行にCREDITまたはDEBITフィールドのいずれかが設定されていますが、両方が同時に設定されることはありません。

2。フィールド区切り文字の変更

これまで見てきたように、paste コマンドは、タブ文字をデフォルトのフィールド区切り文字(「区切り文字」)として使用します。 -dを使用して変更できるもの オプション。代わりにセミコロンを使用したいとします:

# The quotes around the ';' are used to prevent the
# shell to consider that semi-colon as being a command separator
sh$ paste -d ';' *.csv | head -3
ACCOUNTLIB;ACCOUNTNUM;CREDIT;DEBIT
TIDE SCHEDULE;623477;;00000001615,00
VAT BS/ENC;445452;;00000000323,00

sedを追加する必要はありません 使用したセパレータは印刷可能な文字であるため、ここでパイプラインの最後にあるコマンド。とにかく、結果は同じです。特定の行で、各フィールドは1文字の区切り文字を使用して隣接するフィールドから分離されます。

3。シリアルモードを使用したデータの転置

上記の例には、1つの共通点があります。paste コマンドは、すべての入力ファイルを並行して読み取ります。これは、出力で行ごとにそれらをマージできるようにするために必要なものです。

ただし、paste コマンドは、いわゆるシリアルモードでも動作します。 -sを使用して有効化 国旗。その名前が示すように、シリアルモードでは、paste コマンドは、入力ファイルを次々に読み取ります。最初の入力ファイルの内容は、最初の出力行を生成するために使用されます。次に、2番目の入力ファイルの内容を使用して2番目の出力行が生成され、以下同様に続きます。これは、出力に入力に含まれるファイルと同じ数の行が含まれることも意味します。

より正式には、ファイル Nから取得したデータ Nとして表示されます シリアルモードの出力の3行目ですが、 Nとして表示されます。 デフォルトの「並列」モードの列。数学的には、シリアルモードで取得されたテーブルは、デフォルトモードで作成されたテーブルの転置です(その逆)。

それを説明するために、データの小さなサブサンプルを考えてみましょう。

sh$ head -5 ACCOUNTLIB.csv | tee ACCOUNTLIB.sample
ACCOUNTLIB
TIDE SCHEDULE
VAT BS/ENC
PAYABLES
ACCOMMODATION GUIDE
sh$ head -5 ACCOUNTNUM.csv | tee ACCOUNTNUM.sample
ACCOUNTNUM
623477
445452
4356
623372

デフォルト(「並列」)モードでは、入力ファイルのデータは出力の列として機能し、2列×5行のテーブルを生成します。

sh$ paste *.sample
ACCOUNTLIB    ACCOUNTNUM
TIDE SCHEDULE    623477
VAT BS/ENC    445452
PAYABLES    4356
ACCOMMODATION GUIDE    623372

ただし、シリアルモードでは、入力ファイルのデータは行として表示され、5列×2行のテーブルが生成されます。

sh$ paste -s *.sample
ACCOUNTLIB    TIDE SCHEDULE    VAT BS/ENC    PAYABLES    ACCOMMODATION GUIDE
ACCOUNTNUM    623477    445452    4356    623372

4。標準入力の操作

多くの標準ユーティリティと同様に、paste コマンドは、標準入力を使用してデータを読み取ることができます。引数としてファイル名が指定されていない場合は暗黙的に、または特別な-を使用して明示的に ファイル名。どうやら、これはそれほど有用ではありません:

# Here, the paste command is useless
head -5 ACCOUNTLIB.csv | paste
ACCOUNTLIB
TIDE SCHEDULE
VAT BS/ENC
PAYABLES
ACCOMMODATION GUIDE

自分でテストすることをお勧めしますが、次の構文でも同じ結果が得られるはずです。その場合、pasteコマンドは役に立たなくなります。

head -5 ACCOUNTLIB.csv | paste -

では、標準入力からデータを読み取るポイントは何でしょうか?さて、-sで フラグを立てると、これから見ていくように、物事はもっと面白くなります。

4.1。ファイルの行を結合する

数段落前に見たように、シリアルモードでは、pasteコマンドは入力ファイルのすべての行を同じ出力行に書き込みます。これにより、標準入力から読み取られたすべての行を1つの(場合によっては非常に長い)出力行に結合する簡単な方法が得られます。

sh$ head -5 ACCOUNTLIB.csv | paste -s -d':'
ACCOUNTLIB:TIDE SCHEDULE:VAT BS/ENC:PAYABLES:ACCOMMODATION GUIDE

これは、trを使用して実行できることとほとんど同じです。 コマンドですが、1つの違いがあります。 diffを使用しましょう それを見つけるためのユーティリティ:

sh$ diff <(head -5 ACCOUNTLIB.csv | paste -s -d':') \
         <(head -5 ACCOUNTLIB.csv | tr '\n' ':')
1c1
< ACCOUNTLIB:TIDE SCHEDULE:VAT BS/ENC:PAYABLES:ACCOMMODATION GUIDE
---
> ACCOUNTLIB:TIDE SCHEDULE:VAT BS/ENC:PAYABLES:ACCOMMODATION GUIDE:
\ No newline at end of file

diffによって報告されたとおり ユーティリティ、trを見ることができます コマンドは、最後の区切り文字を含め、改行文字のすべてのインスタンスを指定された区切り文字に置き換えました。一方、paste コマンドは、最後の改行文字を変更せずに保持しました。したがって、最後のフィールドの後に区切り文字が必要かどうかに応じて、いずれかのコマンドを使用します。

4.2。 1つの入力ファイルの複数列のフォーマット

Open Groupの仕様によると、「標準入力は一度に1行ずつ読み取る必要があります」 paste 指図。したがって、-の複数のオカレンスを渡す pasteへの引数としての特別なファイル名 コマンドを実行すると、入力の連続する行が同じ出力行に書き込まれます。

sh$ seq 9 | paste - - -
1    2    3
4    5    6
7    8    9

より明確にするために、以下の2つのコマンドの違いを調べることをお勧めします。最初のケースでは、pasteコマンドが同じファイルを3回開くため、出力でデータが重複します。一方、2番目のケースでは、ACCOUNTLIBファイルは(シェルによって)1回だけ開かれますが、(pasteによって)各行に対して3回読み取られます。 コマンド)、ファイルの内容が3つの列として表示されます:

sh$ paste ACCOUNTLIB.csv ACCOUNTLIB.csv ACCOUNTLIB.csv | head -2
ACCOUNTLIB    ACCOUNTLIB    ACCOUNTLIB
TIDE SCHEDULE    TIDE SCHEDULE    TIDE SCHEDULE

sh$ paste - - - < ACCOUNTLIB.csv | head -2
ACCOUNTLIB    TIDE SCHEDULE    VAT BS/ENC
PAYABLES    ACCOMMODATION GUIDE    VAT BS/ENC

pasteの動作を考えると 標準入力から読み取る場合のコマンドは、通常 ではありません。 複数の-を使用することをお勧めします シリアルモードでの特別なファイル名。その場合、最初のオカレンスは最後まで標準入力を読み取り、その後の-のオカレンスはそれを読み取ります。 すでに使い果たされた入力ストリームから読み取るため、データが利用できなくなります。

# The following command will produce 3 lines of output.
# But the first one exhausted the standard input,
# so the remaining two lines are empty
sh$ seq 9 | paste -s - - -
1    2    3    4    5    6    7    8    9

5。異なる長さのファイルの操作

pasteのOpenGroup仕様 ユーティリティは非常に明確です:

1つ以上の入力ファイルでファイルの終わりの状態が検出されたが、すべての入力ファイルではない場合、貼り付けは、ファイルの終わりが検出されたファイルから空の行が読み取られたかのように動作します。 -sオプションが指定されています。

したがって、動作は予想どおりです。欠落しているデータは「空の」コンテンツに置き換えられます。その動作を説明するために、さらにいくつかのトランザクションを「データベース」に記録しましょう。元のファイルをそのまま維持するために、データのコピーを作成します:

# Copy files
sh$ for f in ACCOUNTNUM ACCOUNTLIB CREDIT DEBIT; do
  cp ${f}.csv NEW${f}.csv
done

# Update the copy
sh$ cat - << EOF >> NEWACCOUNTNUM.csv
1080
4356
EOF

sh$ cat - << EOF >> NEWDEBIT.csv
00000001207,35

EOF

sh$ cat - << EOF >> NEWCREDIT.csv

00000001207,35
EOF

これらの更新により、アカウント#1080からアカウント#4356への新しい資本移動が登録されました。ただし、お気づきかもしれませんが、私はわざわざACCOUNTLIBファイルを更新しませんでした。 pasteなので、これはそれほど大きな問題ではないようです。 コマンドは、欠落している行を空のデータに置き換えます:

sh$ paste -d';' NEWACCOUNTNUM.csv \
                NEWACCOUNTLIB.csv \
                NEWDEBIT.csv \
                NEWCREDIT.csv | tail
4356;PAYABLES;;00000000402,03
613866;RENTAL COSTS;00000000018,00;
4356;PAYABLES;;00000000018,00
657991;MISCELLANEOUS CHARGES;00000000015,00;
445333;VAT BS/DEBIT;00000000003,00;
4356;PAYABLES;;00000000018,00
626510;LANDLINE TELEPHONE;00000000069,14;
445452;VAT BS/ENC;00000000013,83;
1080;;00000001207,35; # <-- the account label is missing here
4356;;;00000001207,35 # <-- the account label is missing here

ただし、pasteに注意してください コマンドは、物理的によってのみ行を照合できます 位置:ファイルが他のファイルより「短い」ことだけがわかります。 どこではありません データがありません。そのため、出力の最後に常に空白フィールドが追加されます。これにより、データに予期しないオフセットが発生する可能性があります。さらに別のトランザクションを追加して、それを明らかにしましょう:

sh$ cat << EOF >> NEWACCOUNTNUM.csv
4356
3465
EOF

sh$ cat << EOF >> NEWACCOUNTLIB.csv
PAYABLES
WEB HOSTING
EOF

sh$ cat << EOF >> NEWDEBIT.csv

00000000706,48
EOF

sh$ cat << EOF >> NEWCREDIT.csv
00000000706,48

EOF

今回は、アカウント番号(ACCOUNTNUM)とそれに対応するラベル(ACCOUNTLIB)、およびCREDITデータファイルとDEBITデータファイルの両方を適切に更新したため、より厳密になりました。ただし、前のレコードにはデータが欠落していたため、paste コマンドは、関連するフィールドを同じ行に保持できなくなりました:

sh$ paste -d';' NEWACCOUNTNUM.csv \
                NEWACCOUNTLIB.csv \
                NEWDEBIT.csv \
                NEWCREDIT.csv | tail
4356;PAYABLES;;00000000018,00
657991;MISCELLANEOUS CHARGES;00000000015,00;
445333;VAT BS/DEBIT;00000000003,00;
4356;PAYABLES;;00000000018,00
626510;LANDLINE TELEPHONE;00000000069,14;
445452;VAT BS/ENC;00000000013,83;
1080;PAYABLES;00000001207,35;
4356;WEB HOSTING;;00000001207,35
4356;;;00000000706,48
3465;;00000000706,48;

ご覧のとおり、アカウント#4356は「WEBHOSTING」というラベルで報告されていますが、実際には、後者はアカウント#3465に対応する行に表示されます。

結論として、pasteの代わりに、欠落しているデータを処理する必要がある場合 joinの使用を検討する必要があるコマンド 後者は、入力ファイル内の位置に基づくのではなく、コンテンツに基づいて行を照合するため、ユーティリティです。これにより、「データベース」スタイルのアプリケーションにはるかに適したものになります。 joinに関する動画をすでに公開しています コマンドですが、それはおそらくそれ自体の記事に値するはずなので、そのトピックに興味がある場合はお知らせください!

6。区切り文字を循環する

圧倒的多数のユースケースでは、区切り文字として1文字のみを指定します。これが私たちが今までやってきたことです。ただし、-dの後に複数の文字を指定した場合 オプションの場合、貼り付けコマンドはそれらを循環します。最初の文字は行の最初のフィールド区切り文字として使用され、2番目の文字は2番目のフィールド区切り文字として使用されます。

sh$ paste -d':+-' ACCOUNT*.csv CREDIT.csv DEBIT.csv | head -5
ACCOUNTLIB:ACCOUNT NUM+CREDIT-DEBIT
TIDE SCHEDULE:623477+-00000001615,00
VAT BS/ENC:445452+-00000000323,00
PAYABLES:4356+00000001938,00-
ACCOMODATION GUIDE:623372+-00000001333,00

フィールド区切り文字はにのみ表示できます 田畑。行の終わりではありません。また、指定された2つのフィールドの間に複数の区切り文字を挿入することはできません。これらの制限を克服するためのトリックとして、/dev/nullを使用できます。 追加の区切り文字が必要な場合の追加入力としての特別なファイル:

# Display the opening bracket between the
# ACCOUNTLIB field and the ACCOUNTNUM field, and
# the closing bracket between the ACCOUNTNUM field
# and the empty `/dev/null` field:
sh$ paste  -d'()' \
           ACCOUNT*.csv /dev/null | head -5
ACCOUNTLIB(ACCOUNTNUM)
TIDE SCHEDULE(623477)
VAT BS/ENC(445452)
PAYABLES(4356)
ACCOMODATION GUIDE(623372)

悪用する可能性のあるもの:

sh$ paste -d'# is ' \
          - ACCOUNTNUM.csv - - - ACCOUNTLIB.csv < /dev/null | tail -5
#657991 is MISCELLANEOUS CHARGES
#445333 is VAT BS/DEBIT
#4356 is PAYABLES
#626510 is LANDLINE TELEPHONE
#445452 is VAT BS/ENC

ただし、言うまでもなく、そのレベルの複雑さに達した場合は、pasteの手がかりになる可能性があります。 ユーティリティは必ずしも仕事に最適なツールではありませんでした。その場合は、sedのようなものを検討する価値があるかもしれません。 またはawkコマンド。

しかし、出力に行を表示するために必要な数よりも少ない区切り文字がリストに含まれている場合はどうなるでしょうか。興味深いことに、paste コマンドはそれらを「循環」します。したがって、リストが使い果たされると、paste コマンドは最初の区切り文字に戻ります。これは、おそらくクリエイティブな使用法への扉を開くものです。私自身の時点では、私のデータを考えると、その機能で本当に役立つものを作ることはできませんでした。したがって、次の少し遠い例に満足する必要があります。ただし、バックスラッシュを2倍にする必要があると言うのは良い機会だったので、時間を完全に無駄にすることはありません(\\ )区切り文字として使用する場合:

sh$ paste -d'/\\' \
          - ACCOUNT*.csv CREDIT.csv DEBIT.csv - < /dev/null | tail -5
/MISCELLANEOUS CHARGES\657991/\00000000015,00/
/VAT BS/DEBIT\445333/\00000000003,00/
/PAYABLES\4356/00000000018,00\/
/LANDLINE TELEPHONE\626510/\00000000069,14/
/VAT BS/ENC\445452/\00000000013,83/

7。マルチバイト文字の区切り文字

ほとんどの標準的なUnixユーティリティと同様に、pasteコマンドは、1文字が1バイトに相当するときに発生します。しかし、これはもはや当てはまりません。今日、多くのシステムはデフォルトでUTF-8可変長エンコーディングを使用しています。 UTF-8では、文字は1、2、3、または4バイトで表すことができます。これにより、従来の1バイトのUS-ASCII文字エンコードとの昇順の互換性を維持しながら、さまざまな人間の文章、および大量の記号や絵文字を同じテキストファイルに混在させることができます。

たとえば、フィールドセパレータとしてWHITE DIAMOND(◇U + 25C7)を使用したいとします。 UTF-8では、この文字は3バイトのe2 97 87を使用してエンコードされます。 。この文字はキーボードから取得するのが難しい場合があるため、自分で試してみたい場合は、以下のコードブロックからコピーして貼り付けることをお勧めします。

# The sed part is only used as a little trick to add the
# row number as the first field in the output
sh$ sed -n = ACCOUNTNUM.csv |
       paste -d'◇' - ACCOUNT*.csv | tail -5
26�MISCELLANEOUS CHARGES�657991
27�VAT BS/DEBIT�445333
28�PAYABLES�4356
29�LANDLINE TELEPHONE�626510
30�VAT BS/ENC�445452

かなり欺瞞的ですね。予想される白いひし形の代わりに、その「疑問符」記号があります(少なくとも、これが私のシステムでの表示方法です)。ただし、これは「ランダム」な文字ではありません。これは、「システムがデータのストリームを正しい記号にレンダリングできない場合の問題を示すために」使用されるUnicode置換文字です。 。では、何が問題になっていますか?

繰り返しになりますが、出力の生のバイナリコンテンツを調べると、いくつかの手がかりが得られます。

sh$ sed -n = ACCOUNTNUM.csv | paste -d'◇' - ACCOUNT*.csv | tail -5 | hexdump -C
00000000  32 36 e2 4d 49 53 43 45  4c 4c 41 4e 45 4f 55 53  |26.MISCELLANEOUS|
00000010  20 43 48 41 52 47 45 53  97 36 35 37 39 39 31 0a  | CHARGES.657991.|
00000020  32 37 e2 56 41 54 20 42  53 2f 44 45 42 49 54 97  |27.VAT BS/DEBIT.|
00000030  34 34 35 33 33 33 0a 32  38 e2 50 41 59 41 42 4c  |445333.28.PAYABL|
00000040  45 53 97 34 33 35 36 0a  32 39 e2 4c 41 4e 44 4c  |ES.4356.29.LANDL|
00000050  49 4e 45 20 54 45 4c 45  50 48 4f 4e 45 97 36 32  |INE TELEPHONE.62|
00000060  36 35 31 30 0a 33 30 e2  56 41 54 20 42 53 2f 45  |6510.30.VAT BS/E|
00000070  4e 43 97 34 34 35 34 35  32 0a                    |NC.445452.|
0000007a

上記の16進ダンプを使用して練習する機会がすでにあったので、バイトストリーム内のフィールド区切り文字を見つけるのに十分なほど目を鋭くする必要があります。よく見ると、行番号がバイトe2の後にフィールドセパレータが表示されます。 。ただし、調査を続けると、2番目のフィールド区切り文字が97であることがわかります。 。 pasteだけでなく コマンドは必要な文字を出力しませんでしたが、区切り文字と同じバイトをどこでも使用しませんでしたか?!?

ちょっと待ってください:それは私たちがすでに話していることを思い出させませんか?そして、それらの2バイトのe2 97 、彼らはあなたにいくらか馴染みがありませんか?まあ、なじみはおそらく少し多すぎますが、いくつかの段落に戻ると、どこかで言及されていることに気付くかもしれません…

それで、あなたはそれがどこにあったかを見つけましたか?以前、UTF-8で言ったように、白いひし形は3バイトのe2 97 87としてエンコードされます。 。そして確かに、paste コマンドは、そのシーケンスを3バイト文字全体としてではなく、3つの独立したと見なしました。 バイトなど、最初のバイトを最初のフィールドセパレータとして使用し、次に2番目のバイトを2番目のフィールドセパレータとして使用しました。

入力データにもう1つの列を追加して、その実験を再実行します。 3番目のフィールドセパレータが87であることがわかります。 —ホワイトダイヤモンドのUTF-8表現の3番目のバイト。

わかりました、それが説明です:paste コマンドは、1バイトの「文字」のみを区切り文字として受け入れます。 /dev/nullを使用する以外に、この制限を克服する方法がわからないため、これは特に厄介です。 私がすでにあなたに与えたトリック:

sh$ sed -n = ACCOUNTNUM.csv |
    paste  -d'◇' \
           - /dev/null /dev/null \
           ACCOUNTLIB.csv /dev/null /dev/null \
           ACCOUNTNUM.csv | tail -5
26◇MISCELLANEOUS CHARGES◇657991
27◇VAT BS/DEBIT◇445333
28◇PAYABLES◇4356
29◇LANDLINE TELEPHONE◇626510
30◇VAT BS/ENC◇445452

cutに関する以前の記事を読んだ場合 コマンド、あなたは私がそのツールのGNU実装で同様の問題を抱えていたことを覚えているかもしれません。しかし、その時、OpenBSDの実装がLC_CTYPEを正しく考慮していることに気づきました。 マルチバイト文字を識別するためのロケール設定。好奇心から、pasteをテストしました OpenBSDでもコマンド。残念ながら、pasteの仕様にもかかわらず、今回のDebianボックスと同じ結果になりました "テキストデータのバイトシーケンスを文字として解釈するためのロケール(たとえば、引数および入力ファイルのマルチバイト文字ではなくシングルバイト)"を決定するものとしてLC_CTYPE環境変数に言及するユーティリティ 。私の経験から、pasteのすべての主要な実装 ユーティリティは現在、区切り文字リストのマルチバイト文字を無視し、1バイトの区切り文字を想定しています。しかし、私は*nixプラットフォームのすべての種類についてそれをテストしたとは主張しません。したがって、ここで何かを見逃した場合は、コメントセクションを使用して修正することを躊躇しないでください!

ボーナスのヒント:\0の落とし穴を回避する

歴史的な理由から:

コマンド:
past -d“ \ 0”…paste -d“”…
は必ずしも同等ではありません。後者は、IEEE Std 1003.1-2001のこのボリュームでは指定されておらず、エラーが発生する可能性があります。過去のバージョンの貼り付けは構文ガイドラインに準拠していなかったため、構文「\ 0」は「区切り文字なし」を意味するために使用され、コマンドは次のとおりです。
past -d””…
getopt()で適切に処理できませんでした。

したがって、区切り文字を使用せずにファイルを貼り付ける移植可能な方法は、\0を指定することです。 デリミタ。多くのコマンドでは、\0であるため、これはやや直感に反します。 NUL文字を意味します。これは、テキストコンテンツと衝突してはならないゼロのみで構成されるバイトとしてエンコードされた文字です。

NUL文字は、特にデータに任意の文字が含まれている場合(ファイル名やユーザー提供のデータを操作する場合など)に便利な区切り文字であることがわかります。残念ながら、pasteでフィールド区切り文字としてNUL文字を使用する方法を知りません。 指図。しかし、多分あなたはそれをする方法を知っていますか?その場合は、コマンドセクションで解決策を読んでいただければ幸いです。

一方、paste GNUCoreutilsの実装部分には非標準の-zがあります 行区切り文字の改行文字からNUL文字に切り替えるオプション。ただし、その場合、NUL文字が行区切り文字として使用されます両方 入力と出力用。したがって、その機能をテストするには、最初に入力ファイルのゼロで終了するバージョンが必要です。

sh$ tr '\n' '\0' < ACCOUNTLIB.csv > ACCOUNTLIB.zero
sh$ tr '\n' '\0' < ACCOUNTNUM.csv > ACCOUNTNUM.zero

プロセスで何が変更されたかを確認するには、hexdumpを使用できます。 ファイルの生のバイナリコンテンツを調べるユーティリティ:

sh$ hexdump -C ACCOUNTLIB.csv | head -5
00000000  41 43 43 4f 55 4e 54 4c  49 42 0a 54 49 44 45 20  |ACCOUNTLIB.TIDE |
00000010  53 43 48 45 44 55 4c 45  0a 56 41 54 20 42 53 2f  |SCHEDULE.VAT BS/|
00000020  45 4e 43 0a 50 41 59 41  42 4c 45 53 0a 41 43 43  |ENC.PAYABLES.ACC|
00000030  4f 4d 4f 44 41 54 49 4f  4e 20 47 55 49 44 45 0a  |OMODATION GUIDE.|
00000040  56 41 54 20 42 53 2f 45  4e 43 0a 50 41 59 41 42  |VAT BS/ENC.PAYAB|
sh$ hexdump -C ACCOUNTLIB.zero | head -5
00000000  41 43 43 4f 55 4e 54 4c  49 42 00 54 49 44 45 20  |ACCOUNTLIB.TIDE |
00000010  53 43 48 45 44 55 4c 45  00 56 41 54 20 42 53 2f  |SCHEDULE.VAT BS/|
00000020  45 4e 43 00 50 41 59 41  42 4c 45 53 00 41 43 43  |ENC.PAYABLES.ACC|
00000030  4f 4d 4f 44 41 54 49 4f  4e 20 47 55 49 44 45 00  |OMODATION GUIDE.|
00000040  56 41 54 20 42 53 2f 45  4e 43 00 50 41 59 41 42  |VAT BS/ENC.PAYAB|

上記の2つの16進ダンプを自分で比較して、「。zero」ファイルと元のテキストファイルの違いを特定します。ヒントとして、改行は0aとしてエンコードされていると言えます。 バイト。

うまくいけば、「。zero」入力ファイルでNUL文字を見つけるのに必要な時間がかかりました。とにかく、入力ファイルのゼロで終了するバージョンができたので、-zを使用できます。 pasteのオプション これらのデータを処理するコマンド。出力とゼロで終了する結果を生成します。

# Hint: in the hexadecimal dump:
#  the byte 00 is the NUL character
#  the byte 09 is the TAB character
# Look at any ASCII table to find the mapping
# for the letters or other symbols
# (https://en.wikipedia.org/wiki/ASCII#Character_set)
sh$ paste -z *.zero | hexdump -C | head -5
00000000  41 43 43 4f 55 4e 54 4c  49 42 09 41 43 43 4f 55  |ACCOUNTLIB.ACCOU|
00000010  4e 54 4e 55 4d 00 54 49  44 45 20 53 43 48 45 44  |NTNUM.TIDE SCHED|
00000020  55 4c 45 09 36 32 33 34  37 37 00 56 41 54 20 42  |ULE.623477.VAT B|
00000030  53 2f 45 4e 43 09 34 34  35 34 35 32 00 50 41 59  |S/ENC.445452.PAY|
00000040  41 42 4c 45 53 09 34 33  35 36 00 41 43 43 4f 4d  |ABLES.4356.ACCOM|

# Using the `tr` utility, we can map \0 to newline
# in order to display the output on the console:
sh$ paste -z *.zero | tr '\0' '\n' | head -3
ACCOUNTLIB    ACCOUNTNUM
TIDE SCHEDULE    623477
VAT BS/ENC    445452

入力ファイルのデータに改行が埋め込まれていないため、-z ここでは、オプションの有用性は限られています。しかし、上記の説明に基づいて、次の例が「期待どおりに」機能する理由を理解してみましょう。サンプルファイルをダウンロードし、hexdumpを使用してバイトレベルで調べる必要があることを完全に理解するには 上記で行ったユーティリティ:

# Somehow, the head utility seems to be confused
# by the ACCOUNTS file content (I wonder why?;)
sh$ head -3 CATEGORIES ACCOUNTS
==> CATEGORIES <==
PRIVATE
ACCOMMODATION GUIDE
SHARED

==> ACCOUNTS <==
6233726230846265106159126579914356613866618193623477623795445333445452605751
# The output is quite satisfactory, putting the account number
# after the account name and keeping things surprisingly nicely formatted:
sh$ paste -z -d':' CATEGORIES ACCOUNTS | tr '\0' '\n' | head -5
PRIVATE
ACCOMMODATION GUIDE:623372

SHARED
ADVERTISEMENTS:623084

さらに何ですか?

paste コマンドは、区切られたテキスト出力のみを生成します。ただし、紹介ビデオの最後に示されているように、システムがBSDcolumnをサポートしている場合 ユーティリティを使用すると、pasteを変換することで、適切にフォーマットされたテーブルを取得できます。 固定幅のテキスト形式へのコマンド出力。しかし、それは今後の記事の主題になります。引き続きご期待ください。いつものように、お気に入りのウェブサイトやソーシャルメディアでその記事を共有することを忘れないでください!


Linux
  1. Linux Catコマンド:使用法と例

  2. Linux Sedコマンド:使用法と例

  3. Linuxでのmvコマンド:7つの重要な例

  1. Linuxコマンド:jobs、bg、およびfg

  2. Linux AWKコマンド–LinuxおよびUnixの使用構文の例

  3. 4LinuxでのCutコマンドの基本的かつ実用的な使用法

  1. Linuxでの「cd」コマンドの5つの実用例

  2. LinuxでのTracerouteコマンドの16の実用例

  3. Linuxdfコマンド