2025/02/16(日)Cygwin 3.5.7 における日本語変換ソフト

Cygwin 3.5.7 の標準インストーラでインストール可能な日本語文字コードを扱える文字エンコード変換ソフトのパッケージについて。

標準には無いパッケージ

nkf

ただし、ソースからコンパイルしてインストールすることは可能。
$ tar xzf nkf-2.1.5.tar.gz
$ cd nkf-2_1_5/
$ make
cc -g -O2 -Wall -pedantic -c nkf.c
cc -g -O2 -Wall -pedantic -c utf8tbl.c
cc -g -O2 -Wall -pedantic  -o nkf nkf.o utf8tbl.o
$ make install
mkdir /usr/local/bin
mkdir: ディレクトリ `/usr/local/bin' を作成できません: File exists
make: [Makefile:49: install-main] エラー 1 (無視されました)
cp -f nkf /usr/local/bin/
mkdir /usr/local/man
mkdir /usr/local/man/man1
cp -f nkf.1 /usr/local/man/man1/
mkdir /usr/local/man/ja
mkdir /usr/local/man/ja/man1
cp -f nkf.1j /usr/local/man/ja/man1/nkf.1
$ nkf
$ nkf --help
Usage:  nkf -[flags] [--] [in file] .. [out file for -O flag]
 j/s/e/w  Specify output encoding ISO-2022-JP, Shift_JIS, EUC-JP
          UTF options is -w[8[0],{16,32}[{B,L}[0]]]
 J/S/E/W  Specify input encoding ISO-2022-JP, Shift_JIS, EUC-JP
          UTF option is -W[8,[16,32][B,L]]
 m[BQSN0] MIME decode [B:base64,Q:quoted,S:strict,N:nonstrict,0:no decode]
 M[BQ]    MIME encode [B:base64 Q:quoted]
 f/F      Folding: -f60 or -f or -f60-10 (fold margin 10) F preserve nl
 Z[0-4]   Default/0: Convert JISX0208 Alphabet to ASCII
          1: Kankaku to one space  2: to two spaces  3: HTML Entity
          4: JISX0208 Katakana to JISX0201 Katakana
 X,x      Convert Halfwidth Katakana to Fullwidth or preserve it
 O        Output to File (DEFAULT 'nkf.out')
 L[uwm]   Line mode u:LF w:CRLF m:CR (DEFAULT noconversion)
 --ic=<encoding>        Specify the input encoding
 --oc=<encoding>        Specify the output encoding
 --hiragana --katakana  Hiragana/Katakana Conversion
 --katakana-hiragana    Converts each other
 --{cap, url}-input     Convert hex after ':' or '%'
 --numchar-input        Convert Unicode Character Reference
 --fb-{skip, html, xml, perl, java, subchar}
                        Specify unassigned character's replacement
 --in-place[=SUF]       Overwrite original files
 --overwrite[=SUF]      Preserve timestamp of original files
 -g --guess             Guess the input code
 -v --version           Print the version
 --help/-V              Print this help / configuration
Network Kanji Filter Version 2.1.5 (2018-12-15)
Copyright (C) 1987, FUJITSU LTD. (I.Ichikawa).
Copyright (C) 1996-2018, The nkf Project.
$

存在するパッケージ

lv

ビューアーだが、変換プログラムとしても使用できる。


$ cat file | lv -Os | cat
指定できる文字コード
       coding-system:
              a: auto-select
              c: iso-2022-cn
              j: iso-2022-jp
              k: iso-2022-kr
              ec: euc-china
              ej: euc-japan
              ek: euc-korea
              et: euc-taiwan
              u7: UTF-7
              u8: UTF-8
              l1..9: iso-8859-1..9
              l0: iso-8859-10
              lb,ld,le,lf,lg: iso-8859-11,13,14,15,16
              s: shift-jis
              b: big5
              h: HZ
              r: raw mode


libiconv

libiconv2 パッケージではダメ。
libiconv を入れること。GNU libiconv 実装の iconv コマンドが使えるようになる。
$ iconv -l | egrep -i 'jis|2022-?jp|20932' | egrep -vi 'sjis|shift|euc'
ISO-IR-14 ISO646-JP JIS_C6220-1969-RO JP CSISO14JISC6220RO
JIS0201 JISX0201-1976 JISX0201.1976-0 JIS_X0201 X0201 CSHALFWIDTHKATAKANA
ISO-IR-87 JIS0208 JISX0208.1983-0 JISX0208.1990-0 JIS_C6226-1983 JIS_X0208 JIS_X0208-1983 JIS_X0208-1990 X0208 CSISO87JISX0208
ISO-IR-159 JIS0212 JISX0212.1990-0 JIS_X0212 JIS_X0212-1990 JIS_X0212.1990-0 X0212 CSISO159JISX02121990
ISO-2022-JP ISO2022JP CSISO2022JP
ISO-2022-JP-1
ISO-2022-JP-2 CSISO2022JP2
CP50221 ISO-2022-JP-ESC ISO-2022-JP-MS
ISO-2022-JP-2004 ISO-2022-JP-3
$
$ iconv -l | egrep -i 'euc' | egrep -i 'jp|jis'
CP51932 EUC-JP EUCJP EUC_JP EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE CSEUCPKDFMTJAPANESE
EUC-JIS-2004 EUC-JISX0213
$
$ iconv -l | egrep -i 'sjis|shift|932|31j'  | grep -v 51932
MS_KANJI SHIFT-JIS SHIFT_JIS SJIS CSSHIFTJIS
CP932 WINDOWS-31J
SHIFT_JIS-2004 SHIFT_JISX0213
$

piconv (perL)

perl に付属の iconv コマンド。
$ piconv -l | grep -i jis | egrep -iv 'shift|sjis'
7bit-jis
jis0201-raw
jis0208-raw
jis0212-raw
$
$ piconv -l | egrep -i 'jis|31j|932' | egrep -i 'shift|sjis'
shiftjis
$
$ piconv -l | egrep -i 'euc' | egrep -v -e '[-_](cn|tw|kr)'
euc-jp
$

2025/02/12(水)Cygwin 3.5.7 における日本語ファイル名の扱い


Cygwinと日本語ファイル名

久しぶりに家のPCにCygwinを入れたら日本語ファイル名の扱いが変な感じなのでメモ。

検証環境は以下の通り。
CYGWIN_NT-10.0-19045 hostname 3.5.7-1.x86_64 2025-01-29 19:46 UTC x86_64 Cygwin

端末は TeraTerm 5.4-dev (開発版snapshot)

環境変数LANGについて記載している場合、端末から入力した日本語ファイル名もそのLANGに沿った文字コードで入力している。
元々 Cygwin で日本語ファイル名を扱わないようにしていたので、元々この挙動なのか、そうでないのかはわからない。



標準系コマンド

どうもWindows と I/O する前に文字コードを変換しているようだ。
環境変数に応じて、どのエンコードのファイル名でも使用できるように思われる。

LANG=ja_JP.UTF-8の時

出力は UTF-8 で正常
ls
echo *
ls *
ls -d * | xargs file --
find
find | cat
find | xargs file --


LANG=ja_JP.SJIS の時

出力は SJIS で正常
ls
echo *
ls *
ls -d * | xargs file --
find
find | cat
find | xargs file --
一部出力に問題あり
ls -l
ファイル名以外にUTF-8が混じる。

LANG=C の時

出力は エスケープ表現で正常
ls
ls *
ls -d * | xargs file --
出力は UTF-8
echo *
一部出力に問題あり
ls -l
ファイル名はエスケープ表現だが、ファイル名以外にUTF-8が混じる。

自作プログラム 1 - ディレクトリエントリ読み込み (readdir())

以下のような単純なプログラムを gcc でコンパイルして使用した。
ソースコード readd.c
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <time.h>

int main()
{

        DIR *dirp;
        struct dirent *dp;
        struct stat st;

        dirp = opendir(".");
        if (dirp == NULL) {
                perror("opendir");
                return 1;
        }
        while ((dp = readdir(dirp)) != NULL) {
                if (dp->d_type & DT_DIR) {
                        printf("<%s>  DIR \t", dp->d_name);
                }
                else {
                        printf("<%s>      \t", dp->d_name);
                }
                if (stat(dp->d_name, &st) == 0) {
                        printf("%lld, %s", st.st_size, ctime(&st.st_mtime));
                }
                else {
                        perror("");
                }
        }
        (void)closedir(dirp);
        return 0;

}
動作結果
locale に関わらず、ファイル名は必ず UTF-8 で出力された。
  • 確認済みlocale
    • LANG=ja_JP.SJIS
    • LANG=ja_JP.UTF-8
    • LANG=C

自作プログラム 2 - ファイル名手動引き渡し (stat())

以下のような単純なプログラムを gcc でコンパイルして使用した。
ソースコード statf.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <time.h>

int main(int argc, char *argv[])
{

        struct stat st;
        int i = 1;

        while (i < argc) {
                if (stat(argv[i], &st) == 0) {
                        printf("<%s> %lld, %s", argv[i], st.st_size, ctime(&st.st_mtime));
                }
                else {
                        perror(argv[i]);
                }
                i++;
        }
        return 0;

}

動作結果

LANG=ja_JP.SJIS
SJIS のファイル名を引き渡したと思われる全てのケースで失敗する。
    • コマンドラインも SJISである。
    • No such file or directory になる。
./statf テスト01.txt
find | xargs ./statf
ls | xargs ./statf
./statf *
おそらくファイル名として UTF-8 を指定する必要がある。
$ ./statf *01.txt
テスト01.txt: No such file or directory
以下のように UTF-8 のファイル名を用意して実行すると成功する。
user@hostname ~/src
$ cat filename.txt
繝せ繝01.xt
user@hostname ~/src
$ ./statf $(cat filename.txt)
<繝せ繝01.xt> 26, Wed Feb 12 19:00:59 2025

user@hostname ~/src
$

LANG=ja_JP.UTF-8
全てのケースで正常に実行される。
./statf テスト01.txt
find | xargs ./statf
ls | xargs ./statf
./statf *

perl

以下の perl コードは SJIS, UTF-8 どちらでも動作した。
perl -e 'while($n=<*.txt>){ print "file=<$n>"; open(F,"<",$n)||die; @b=(<F>);print scalar(@b) ."\n"; close(F) }'
perl -e 'opendir(D,".");while($n=readdir(D)){ print "file=<$n>"; open(F,"<",$n)||die; @b=(<F>);print scalar(@b) ."\n"; close(F) }'

linked library

user@hostname ~/src
$ ldd statf.exe
        ntdll.dll => /cygdrive/c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffa79c90000)
        KERNEL32.DLL => /cygdrive/c/WINDOWS/System32/KERNEL32.DLL (0x7ffa79200000)
        KERNELBASE.dll => /cygdrive/c/WINDOWS/System32/KERNELBASE.dll (0x7ffa777a0000)
        cygwin1.dll => /usr/bin/cygwin1.dll (0x7ffa11520000)

user@hostname ~/src
$ ldd /bin/ls
        ntdll.dll => /cygdrive/c/WINDOWS/SYSTEM32/ntdll.dll (0x7ffa79c90000)
        KERNEL32.DLL => /cygdrive/c/WINDOWS/System32/KERNEL32.DLL (0x7ffa79200000)
        KERNELBASE.dll => /cygdrive/c/WINDOWS/System32/KERNELBASE.dll (0x7ffa777a0000)
        cygintl-8.dll => /usr/bin/cygintl-8.dll (0x3f7ef0000)
        cygwin1.dll => /usr/bin/cygwin1.dll (0x7ffa11520000)
        cygiconv-2.dll => /usr/bin/cygiconv-2.dll (0x3f7fe0000)

まとめ

  • 基本的に Cygwin (v3.5.7) のレイヤーでは UTF-8 でファイル名を受け渡しするのが最も安心できる。
  • ls, find のような基本的なGNUコマンド類が多言語対応しているが、これの UTF-8 以外で出力したファイル名をそのまま UTF-8 ロケールの自作プログラムに渡すと正常動作しない
個人的にはファイル内容に SJIS (Shift_JIS) がある関係上、
ファイル名も SJIS で扱えると助かるのだが、自作プログラムではそのままではうまくいかない事がわかった。