助け合いフォーラム

LPIC

LPIC Lv1-101(Ver5.0)
問題ID : 3688
問題を開く
Windowsのメモ帳で作成したテキストファイル「file1.txt」をLinuxで正しく扱うために、改行コードを変換して「file2.txt」として保存したい。適切なコマンドはどれか。(2つ選択)

正解

tr -d '^M' < file1.txt > file2.txt

sed s/^M//g file1.txt > file2.txt

解説

改行コードと代表的なOSの組み合わせは以下のとおりです。
・CRLF(\r\n):Windows
・LF(\n):Unix OS(Linux, Mac OS Xなど)
・CR(\r):古いMacOS(バージョン9まで)

上記の通りWindowsとLinuxでは改行コードが異なるため、テキストファイルの扱いが問題になる場合があります。CRLF(\r\n)からCR(\r)を取り除くことでLinuxの認識できる改行コード:LF(\n)のみにでき、正しく扱うことができるようになります。(類似問題ID:34286をご参照ください。)
また、CR(キャリッジリターン)は「^M」という制御コードでも表されるため、Windowsで作成したファイルをLinuxのエディタで開くと末尾に「^M」が表示されることがあります。よって、制御コード「^M」を取り除くことでもLinuxの改行コードLF(\n)に変換できます。
なお、Linux上で制御コード「^M」を入力するには、Ctrl+V、Ctrl+Mを続けて押下します。

選択肢を1つずつ確認してみます。

・tr -d '^M' < file1.txt > file2.txt
trコマンドの-dオプションで制御コード「^M」を削除しています。リダイレクト(<)によって「file1.txt」を入力とし、削除した結果を「file2.txt」に出力(>)しています。正しいコマンドです。

・tr -d 'CR' < file1.txt > file2.txt
「CR」という文字列を削除しているだけなので改行コードは変わりません。よって誤りです。

・sed s/^M//g file1.txt > file2.txt
sedコマンドで「file1.txt」中の全ての制御コード「^M」を空白文字に置換(つまり削除)して「file2.txt」に出力しています。正しいコマンドです。

・sed s//^M/g file1.txt > file2.txt
変換前の文字列が空白なのでエラーになります。よって誤りです。

・sed s/CRLF/LF/g file1.txt > file2.txt
全ての「CRLF」という文字列を「LF」という文字列に変換しているだけなので改行コードは変わりません。よって誤りです。

したがって正解は
・sed s/^M//g file1.txt > file2.txt
・tr -d '^M' < file1.txt > file2.txt
です。

以下は実行例です。

参考

正規表現とは、文字列の特定のパターンを認識する為に使用する表現方法です。文字列の検索や置換などを行う際に利用します。正規表現には基本正規表現(BRE: Basic Regular Expression)と拡張正規表現(ERE: Extended Regular Expression)があります。

以下は主な正規表現とその使用例をまとめたものです。


正規表現には次のような基本の概念があります。
・特殊文字
「|」や「\(エスケープ文字)」などのように特殊な意味を持つ文字のことです。

・文字クラス
「[ ]」内の文字集合のことです。

・数量詞
「*」や「+」などのように直前の文字の繰り返し回数を示す文字のことです。

・アンカー
「^」や「$」などのように文字列内での位置を示す文字のことです。

なお、正規表現の「*」と、シェルによって解釈されるメタキャラクタの「*」では意味が異なるので注意してください。シェルは「*」を0文字以上の文字列と解釈します。
正規表現は明示的に「'」(シングルクォーテーション)や「"」(ダブルクォーテーション)の引用符で囲う事ができます。これらの引用符で囲まれた正規表現の記号は、シェルにメタキャラクタとして扱われなくなります。

正規表現を利用する主なコマンドは以下のとおりです。

・grep
ファイルや標準入力から、検索パターンにマッチする文字列を含む行を抽出するコマンド
なお、「-E」オプションを併用すると拡張正規表現が使えます(egrepコマンドと同様)。

・sed
ファイルや標準入力の内容を編集して表示するコマンド

例1)1から5までのいずれかの文字がある行を「test.txt」ファイルから抽出する場合

$ grep '[1-5]' test.txt

例2)「test.txt」ファイルの「#」から始まる行を削除して出力する場合

$ sed '/^#/d' test.txt

基本正規表現と拡張正規表現の違いに注意してください。grepコマンドは、-Eオプションを付けないと検索パターンを基本正規表現と判断しますので、上表の拡張正規表現が使えません。

実行例)


基本正規表現では「?, +」は「\?, \+」とすることで、拡張正規表現と同様の意味を持つようになります。

上に戻る

sedコマンドについて

公開日 2023/02/21

sed s/^M//g file1.txt > file2.txt

が正解となっていますが、「s/^M//」の部分の「^」が正規表現により「行頭のM」という意味になるのでは?と思いました。
私はどのように間違っているのでしょうか?


F FMOURI

2023/02/21 19:19

従って、行末付近にある^Mは置換対象にならないのでは?と思いました

2023/02/21 20:05

また、CR(キャリッジリターン)は「^M」という制御コードでも表されるため、Windowsで作成したファイルをLinuxのエディタで開くと末尾に「^M」が表示されることがあります。よって、制御コード「^M」を取り除くことでもLinuxの改行コードLF(\n)に変換できます。
なお、Linux上で制御コード「^M」を入力するには、Ctrl+V、Ctrl+Mを続けて押下します。

と解説にあるように、この^Mは「普通の文字^と普通の文字Mの並び」ではなく、「Ctrl+V, Ctrl+M で入力した制御コード」です。
制御コードは普通の文字ではないので、「行頭のM」という意味にはなりません。
制御コードのイメージがつかめない場合は、実環境で実際にCtrl+V, Ctrl+M で入力してみてください。

問題文に今回の^Mが制御コードであるということの説明はないのですが、文脈か消去法で理解する必要があります。


コメント

F FMOURI

2023/02/22 19:34

そういうことだったんですね! ITに疎い自分は制御コードだと同じ文字でも^Mは別物になるという可能性すら全く想像つかなかったです 解説にもそのように書いてありませんし、というか知ってる前提で書かれてるようでこれはかなり険しいですね ありがとうございました

この返信に対して
コメントを記入できます

この投稿に対して返信しませんか?