カレントディレクトリに以下のようなファイルがあります。もう十年以上も前のファイルで作った記憶もないものとします。
得体のしれないこれらのファイルがどのようなファイルか確認するには、どうすれば良いでしょうか。
takk~$ ls -l 合計 24 -rwxr-xr-x 1 takkete takkete 70 1月 2 2003 aa -rwxr-xr-x 1 takkete takkete 79 3月 4 2003 bb -rwxr-xr-x 1 takkete takkete 103 4月 5 2003 cc -rwxr-xr-x 1 takkete takkete 69 5月 6 2003 dd -rwxr-xr-x 1 takkete takkete 84 6月 7 2003 ee -rwxr-xr-x 1 takkete takkete 88 7月 8 2003 ff takk~$
まずは、lsの内容をじっくり見ることです。
実行権限(x)がついています。ファイルサイズからしてテキストのように思えますが、fileコマンドを使うと、指定したファイルがどのようなものか簡潔に分かります。
takk~$ file aa aa: Bourne-Again shell script, UTF-8 Unicode text executable takk~$
bashスクリプトであることとUTF-8のテキスト、かつ実行可能ファイルであることがわかりました。
今回のようにファイルが複数あるときは、簡単で、ワイルドカードを指定するだけで良いです。
takk~$ file * aa: Bourne-Again shell script, UTF-8 Unicode text executable bb: Perl script, UTF-8 Unicode text executable cc: Python script, UTF-8 Unicode text executable dd: a /bin/ruby script, UTF-8 Unicode text executable ee: a /usr/bin/groovy script, UTF-8 Unicode text executable ff: awk script, UTF-8 Unicode text executable takk~$
どれか一つ実行してみます。
本来は内容確認してからですが、今回は中身を知ってるファイルなので大丈夫です。実行するときはパス(./)を指定するのを忘れずに。
takk~$ ./ee HELLO takk~$
HELLOと表示されました。ee以外のファイルも同じようにHELLOを表示するスクリプトとなっています。
スクリプトとして実行させるには、ファイルの一行目にシバン(shebang)が必要になります。aaを行番号付きで見てみましょう。
takk~$ cat -n aa 1 #!/bin/bash 2 3 # bashでHELLOと表示するスクリプト 4 5 echo HELLO takk~$
さて、シバンがどのように書かれているか全ファイル一斉にsedを使って確認できないでしょうか。
fileコマンドでは、file *だけで良かったですが、sedでも同じような指定方法で一覧取得は可能でしょうか。sed -n 1p *でどのような表示になるか確認してみましょう。
takk~$ sed -n 1p * #!/bin/bash takk~$
ファイルaaしか表示されませんでした。*を指定してもファイルが連結されていまい、先頭ファイルに該当するaaのさらに一行しか表示されません。
このような場合はheadを梃子にします。headで各ファイルを指定行数で連結した後に、sedで部分抽出します。
sedで部分抽出するためのheadの出力フォーマットを確認するため、行番号付きで表示してみましょう。
takk~$ head -1 * | cat -n 1 ==> aa <== 2 #!/bin/bash 3 4 ==> bb <== 5 #!/usr/bin/perl 6 7 ==> cc <== 8 #!/usr/bin/python 9 10 ==> dd <== 11 #!/bin/ruby 12 13 ==> ee <== 14 #!/usr/bin/groovy 15 16 ==> ff <== 17 #!/usr/bin/awk -f takk~$
3行毎に各ファイルの内容が表示されています。先頭は各ファイルのファイル名が表示されています。
headでの表示フォーマットが確認できたので、次はsedでシバン部分を抽出します。2行目を先頭に3つ飛びでフィルタすれば良いので、sedにて2~3pを指定します。
takk~$ head -1 * | sed -n 2~3p #!/bin/bash #!/usr/bin/perl #!/usr/bin/python #!/bin/ruby #!/usr/bin/groovy #!/usr/bin/awk -f takk~$
シバンの一覧となりました。
一覧にすることで、チェックしやすくなります。
今回間違いを入れていますが、どこが違っているでしょうか。
シバン一覧を得ることができたので、これらのシバンのパスが存在するか確認してみましょう。
まずは、cutコマンドでパスのみ抽出します。
takk~$ head -1 * | sed -n 2~3p | tr '!' ' ' | cut -d' ' -f2 /bin/bash /usr/bin/perl /usr/bin/python /bin/ruby /usr/bin/groovy /usr/bin/awk
!を空白に変えて、cutコマンドでは空白をデリミタ(delimiter 区切り文字、分離記号)をすることで、2列目を抽出することができました。
headとsedとcutでこねくり回したのですが、実はawkではもっと簡潔に書くことができます。
takk~$ awk 'BEGIN{FS="[! ]"}FNR==1{print $2}' * /bin/bash /usr/bin/perl /usr/bin/python /bin/ruby /usr/bin/groovy /usr/bin/awk takk~$
では、このリストを使ってパスの存在チェックをどのように実施すれば良いでしょうか。
すぐ思いつくのは、test -e オプションによるファイルの存在チェックでしょうか。if分岐を書くのも面倒です。
簡単な方法の一つはlsコマンドによるチェックです。lsは指定したファイルが存在しないとエラーを出力してくれます。使ってみましょう。
先ほどcutまでを実行したばかりですので、積極的に!!を使っていきます。
takk~$ !! | xargs ls -1 >/dev/null awk 'BEGIN{FS="[! ]"}FNR==1{print $2}' * | xargs ls -1 >/dev/null ls: /bin/ruby にアクセスできません: そのようなファイルやディレクトリはありません takk~$
はい。/bin/rubyにアクセスできないと表示されました。
これが間違っていました。which rubyで正解パスがわかります。
最後にファイル内にかかれているファイルのタイトル(3行目)を出力して終わりにします。prコマンドを使った方法です。
takk~$ head -3 * | pr -5Jl1 | cut -f1,4 ==> aa <== # bashでHELLOと表示するスクリプト ==> bb <== # perlでHELLOと表示するスクリプト ==> cc <== # pythonでHELLOと表示するスクリプト ==> dd <== # rubyでHELLOと表示するスクリプト ==> ee <== // groovyでHELLOと表示するスクリプト ==> ff <== # awkでHELLOと表示するスクリプト takk~$
コメント