labunix's blog

labunixのラボUnix

参考元となるスクリプトファイルを探すために、システム上のスクリプト言語の分類をしてみる。

■参考元となるスクリプトファイルを探すために、システム上のスクリプト言語の分類をしてみる。
 参考元となるスクリプトファイルをどうやって探すかの一例として。

$ lsb_release -d
Description:	Debian GNU/Linux 10 (buster)

■パスを省略して実行できるコマンドの検索パスは$PATHを使って参照できる。

$ echo $PATH | awk -F\: '{for(a=1;a<=NF;a++){print $a}}'
/home/labunix/myscripts
/usr/local/bin
/usr/bin
/bin
/usr/local/games
/usr/games

■$PATH配下のすべてのフルパスファイル名を取得する。
 通常は$PATH/filenameで十分。一応バックアップや古いコマンド用のディレクトリ配下にファイルがあっても動作するように。

$ echo $PATH | awk -F\: '{for(a=1;a<=NF;a++){print "find "$a" -type f" | "sh"}}'

■まずは素直にスクリプト言語の特徴となる「#!」で始まる行のスクリプト名をオプション付きで集計してみる。

$ awk -F\/ '/^#\!\//{a[$NF]+=1}END{for(n in a){print a[n],n | "sort -ruV"}}' \
  $(echo $PATH | awk -F\: '{for(a=1;a<=NF;a++){print "find "$a" -type f" | "sh"}}')
290 sh
218 perl
80 bash
63 perl -w
51 python3
11 ruby1.8
7 ruby2.1
7 ruby1.9.1
5 sh -e
5 sh -
5 ruby2.5
2 python
2 perl -w 
2 perl 
2 env python
2 env bash
1 sh -- 
1 sh --
1 sh -x
1 sh -f
1 sh -eu
1 ruby
1 python3.7
1 python3 -Es
1 php
1 perl -- # -*- Perl -*-
1 perl -w -pi.old
1 perl -wl
1 perl -T
1 perl5.28-x86_64-linux-gnu
1 make -f
1 gosh
1 env ruby
1 env nickle
1 awk -f

■bashが使われているファイル名を取得する。
 「80 bash」と「2 env bash」の両方が得られる。

$ keyword=bash; awk -v keyword=${keyword} -F\/ '/^#\!\//{if($NF ~ keyword){print FILENAME | "sort -uV"}}' \
  $(echo $PATH | awk -F\: '{for(a=1;a<=NF;a++){print "find "$a" -type f" | "sh"}}') > ${keyword}.txt

$ wc -l ${keyword}.txt
82 bash.txt

■ちょっと脱線。オプション無しの「#!/.*bin」ではじまるスクリプト名を得るには以下のようにする。

$ awk -F\/ '/^#\!\/.*bin/{gsub(".*/| .*","",$0);a[$0]+=1}END{for(n in a){print a[n],n | "sort -ruV"}}' \
  $(echo $PATH | awk -F\: '{for(a=1;a<=NF;a++){print "find "$a" -type f" | "sh"}}')
305 sh
289 perl
80 bash
52 python3
11 ruby1.8
7 ruby2.1
7 ruby1.9.1
6 env
5 ruby2.5
2 python
1 ruby
1 python3.7
1 php
1 perl5.28-x86_64-linux-gnu
1 make
1 gosh
1 awk

■以外と時間がかかるので、「;」区切りでファイル名との組として抽出しておく。

$ awk -F\/ '/^#\!\/.*bin/{gsub(".*/| .*","",$0);a[$0";"FILENAME]+=1}END{for(n in a){print n | "sort -ruV"}}' \
  $(echo $PATH | awk -F\: '{for(a=1;a<=NF;a++){print "find "$a" -type f" | "sh"}}') > keyword-list.txt

■すると、「keyword-list.txt」から、スクリプト名でファイルのフルパス名を検索できるようになる。

$ awk -F\; '$1 ~ /gosh/{print $2}' keyword-list.txt
/usr/bin/gauche-cesconv

■bashのうち、ライセンス識別子(SPDX)=Software Package Data Exchange の記述のあるコマンドを検索する。
 ライセンス識別子を導入していない、古い(または古いルールを使った)スクリプトファイルを除外するため。

 Linux カーネルライセンス規則
 https://doc.kusakata.com/process/license-rules.html

$ awk '/SPDX.License.Identifier/{print FILENAME}' $(awk -F\; '$1 ~ /bash/{print $2}' keyword-list.txt)
/usr/bin/kernel-install
/usr/bin/usb-devices

■スクリプト言語を問わずにリスト化して、一覧からgrepする。

$ awk '/SPDX.License.Identifier/{print FILENAME}' $(awk -F\; '{print $2}' keyword-list.txt) > target.txt
$ grep -f target.txt keyword-list.txt 
sh;/usr/bin/strace-log-merge
sh;/usr/bin/routel
sh;/usr/bin/lorder
sh;/usr/bin/gpg-error-config
sh;/usr/bin/gpgrt-config
bash;/usr/bin/usb-devices
bash;/usr/bin/kernel-install

■ライセンス識別子をファイル名と共に一覧する。

$ awk '/SPDX.License.Identifier/{print FILENAME";"$0}' $(cat target.txt)
/usr/bin/strace-log-merge;# SPDX-License-Identifier: LGPL-2.1-or-later
/usr/bin/routel;# SPDX-License-Identifier: GPL-2.0
/usr/bin/lorder;# SPDX-License-Identifier: BSD-3-Clause
/usr/bin/gpg-error-config;# SPDX-License-Identifier: FSFULLR
/usr/bin/gpgrt-config;# SPDX-License-Identifier: FSFULLR
/usr/bin/usb-devices;# SPDX-License-Identifier: GPL-2.0+
/usr/bin/kernel-install;# SPDX-License-Identifier: LGPL-2.1+

■例えば、FSFULLR(FSF Unlimited License)のライセンスのコマンドを参考にする。

$ awk '/SPDX.License.Identifier/&&/FSFULLR/{print FILENAME";"$0}' $(cat target.txt)
/usr/bin/gpg-error-config;# SPDX-License-Identifier: FSFULLR
/usr/bin/gpgrt-config;# SPDX-License-Identifier: FSFULLR