Linuxでextglobを有効にして「指定したパターン以外のファイル」を指定する

仕事などで日常的にLinuxを利用しているのであれば、ほぼ大半の人がglobを利用した事があるだろう。 globという名前にはあまり馴染みが無いかもしれないが、以下のようにワイルドカードや複数のファイル名を指定したりする機能は使ったことがあるはずだ。

例)「/work」フォルダ配下のファイルを「/work2」に移動する

mv /work/* /work2/

例)「/work」フォルダ配下の「aaa.txt」「bbb.txt」のみを削除する

rm /work/{aaa.txt,bbb.txt}

このような指定方法を可能にしているのがglobという機能になる。 そんなglobを拡張したのが、今回紹介するextglobだ。

このextglobを利用すると、globでは指定が難しかった事、例えば"特定のフォルダ以外を指定する"といった事が簡単に行える。 bashやzshで有効になっているかどうか確認するには、以下のようにコマンドを実行する。有効になっていれば、以下のように出力されるはずだ。

shopt | grep extglob # bashの場合
setopt | grep extendedglob # zshの場合
test@test-vm-ubuntu:~$ shopt | grep extglob
extglob         on

test-vm-ubuntu% setopt | grep extendedglob
extendedglob

もしextglobが有効になっていないならば、以下のようにコマンドを実行して有効化する。 常時利用するならば、bashrcなどに記述しておいても良いだろう。

shopt -s extglob # bashの場合
setopt extendedglob # zshの場合

さて、これでextglobが利用できるようになった。 extglobでは、以下のようにパターン指定を行う。

  • ?(パターン) … 指定したパターンに一致するものを指定
  • *(パターン) … 指定したパターンを0回以上繰り返すものを指定
  • +(パターン) … 指定したパターンを0回以上繰り返すものを指定
  • @(パターン) … 指定したパターンのいずれかに一致するものを指定
  • !(パターン) … 指定したパターンに該当しないものを指定

この中でも特に注目すべきは、「!(パターン)」だろう。 それ以外のものは通常のglobでも指定可能だが、「!(パターン)」に関しては通常のglobでは指定出来ない。

実際に、指定パターン以外のファイルを抽出してみよう。 「/work」フォルダにある、「test.txt」以外のファイルを抽出する。

ls -la /work/!(test.txt)

[root@test-centos7 ~]# ls -la /work
合計 16
drwxr-xr-x.  2 root root 4096  6月  6 12:14 .
drwxr-xr-x. 18 root root 4096  6月  4 06:18 ..
-rw-r--r--.  1 root root    0  6月  6 12:14 aaaaa.txt
-rw-r--r--.  1 root root    0  6月  6 12:14 bbbbb.txt
-rw-r--r--.  1 root root    0  6月  6 12:14 ccccc.txt
-rw-r--r--.  1 root root    0  6月  6 12:14 ddddd.txt
lrwxrwxrwx.  1 root root    8  6月  5 19:29 ln_test.txt -> test.txt
lrwxrwxrwx.  1 root root   17  6月  5 19:30 ln_test.txt2 -> /work/ln_test.txt
-rw-r--r--.  1 root root  108  6月  4 22:31 test.txt
-rw-r--r--.  1 root root  230  6月  4 07:17 test2.txt
[root@test-centos7 ~]# ls -la /work/!(test.txt)
-rw-r--r--. 1 root root   0  6月  6 12:14 /work/aaaaa.txt
-rw-r--r--. 1 root root   0  6月  6 12:14 /work/bbbbb.txt
-rw-r--r--. 1 root root   0  6月  6 12:14 /work/ccccc.txt
-rw-r--r--. 1 root root   0  6月  6 12:14 /work/ddddd.txt
lrwxrwxrwx. 1 root root   8  6月  5 19:29 /work/ln_test.txt -> test.txt
lrwxrwxrwx. 1 root root  17  6月  5 19:30 /work/ln_test.txt2 -> /work/ln_test.txt
-rw-r--r--. 1 root root 230  6月  4 07:17 /work/test2.txt

複数のパターンを指定する場合は、「|(パイプ)」で指定を行う。 例えば、「aaaaa.txt」および「bbbbb.txt」以外を抽出する場合は以下のようにコマンドを実行する。

ls -la /work/!(aaaaa.txt|bbbbb.txt)

[root@test-centos7 ~]# ls -la /work
合計 16
drwxr-xr-x.  2 root root 4096  6月  6 12:14 .
drwxr-xr-x. 18 root root 4096  6月  4 06:18 ..
-rw-r--r--.  1 root root    0  6月  6 12:14 aaaaa.txt
-rw-r--r--.  1 root root    0  6月  6 12:14 bbbbb.txt
-rw-r--r--.  1 root root    0  6月  6 12:14 ccccc.txt
-rw-r--r--.  1 root root    0  6月  6 12:14 ddddd.txt
lrwxrwxrwx.  1 root root    8  6月  5 19:29 ln_test.txt -> test.txt
lrwxrwxrwx.  1 root root   17  6月  5 19:30 ln_test.txt2 -> /work/ln_test.txt
-rw-r--r--.  1 root root  108  6月  4 22:31 test.txt
-rw-r--r--.  1 root root  230  6月  4 07:17 test2.txt
[root@test-centos7 ~]# ls -la /work/!(aaaaa.txt|bbbbb.txt)
-rw-r--r--. 1 root root   0  6月  6 12:14 /work/ccccc.txt
-rw-r--r--. 1 root root   0  6月  6 12:14 /work/ddddd.txt
lrwxrwxrwx. 1 root root   8  6月  5 19:29 /work/ln_test.txt -> test.txt
lrwxrwxrwx. 1 root root  17  6月  5 19:30 /work/ln_test.txt2 -> /work/ln_test.txt
-rw-r--r--. 1 root root 108  6月  4 22:31 /work/test.txt
-rw-r--r--. 1 root root 230  6月  4 07:17 /work/test2.txt

変に長いコードを記述するよりは、このような機能を使って短縮してわかりやすいコードを書いたほうがいいだろう。