trコマンドとsed(y)コマンドの動作の同じところ、違うところ

Bash,CentOS,Docker,Linux,Ubuntu,Zsh

はじめに

tr コマンドは、「文字」を別の「文字」に置き換えるコマンドです。

同じようなコマンドとして、 sed コマンドの y 内部コマンドがあります。

両方のコマンドの挙動を紹介します。

検証環境

$ uname -moi
x86_64 x86_64 GNU/Linux

$ head -n 2 /etc/os-release
NAME="Ubuntu"
VERSION="21.04 (Hirsute Hippo)"

$ bash -version | head -n 1
GNU bash, バージョン 5.1.4(1)-release (x86_64-pc-linux-gnu)

tr コマンド

tr コマンドを使って、 "my name is test." という文字を変換してみます。

tr コマンドは指定された複数の文字を、別の文字に変換するコマンドです。

具体例をもとに挙動を見ていきましょう。

例1

tr コマンドの第1引数と第2引数の文字数が同じ場合には、それぞれの文字位置が変換ルールとして対応します。
以下のルールで変換されます。

  • t => a
  • e => b
  • s => c
$ echo 'my name is test.' | tr 'tes' 'abc'
my namb ic dbcd.

例2

tr コマンドの第2引数が第1引数の文字数よりも小さい場合は、
以下のルールで変換されます。

  • t => a
  • e => b
  • s => b ( 最後の変換後文字が利用される )
$ echo 'my name is test.' | tr 'tes' 'ab'
my namb ib abba.

例3

変換前の文字として同じものが複数登場した場合には、以下のルールで変換されます。

  • t => a
  • e => b
  • s => c
  • t => d ( 後勝ちとなり、こちらのルールが優先される )
$ echo 'my name is test.' | tr 'test' 'abcd'
my namb ic dbcd.

sed (y) コマンド

今度は sed コマンドの例を見ていきます。

例1

sed コマンドの第1引数と第2引数の文字数が同じ場合には、それぞれの文字位置が変換ルールとして対応します。
以下のルールで変換されます。

  • t => a
  • e => b
  • s => c
$ echo 'my name is test.' | sed 'y/tes/abc/'
my namb ic abca.

例2

sed コマンドの第1引数と第2引数の文字数が異なる場合には、エラーとなります。

$ echo 'my name is test.' | sed 'y/tes/ab/'
sed: -e expression #1, char 9: `y' コマンドに対する文字列の長さが異なります

$ echo 'my name is test.' | sed 'y/te/abc/'
sed: -e expression #1, char 9: `y' コマンドに対する文字列の長さが異なります

例3

変換前の文字として同じものが複数登場した場合には、以下のルールで変換されます。

  • t => a ( 先勝ちとなり、こちらのルールが優先される )
  • e => b
  • s => c
  • t => d
$ echo 'my name is test.' | sed 'y/test/abcd/'
my namb ic abca.

ひとこと

個人的には tr コマンドは「変換文字数が間違っていた」場合
や「後勝ちで当初想定していたルールが上書きされてしまう」場合の挙動が直感的ではなく、
sed 'y/.../.../' コマンドのほうが好みです。

とはいえ、 sed 'y/.../.../' コマンドを利用しているコードはほぼ見たことがありません。