lsコマンド(-lオプション)の結果をタブ区切りのCSV形式でファイル出力するシェルスクリプト

いつもお世話になっております。
RfromL.comです。

今回はUNIX系環境の現場に参画した際、確実に使用するコマンド。「ls」コマンドの表示内容をCSV形式で出力するシェルスクリプトについてです。

TABLE OF CONTENTS

1.概要
 1.1.目的
 1.2.使用するlsコマンド
 1.3.編集内容
 1.4.実行環境
2.スクリプト内容
 2.1.処理内容
 2.2.実行形式
 2.3.コード内容
3.実行方法
4.出力結果の使用方法
5.おわりに


1.概要

lsコマンドはUNIX系OSのコマンドで、機能としてはファイル/ディレクトリのリストを表示するコマンドです。
UNIX系OSを採用している現場に参画した際には必ず使用することになります。

1.1.目的

lsコマンドの実行において、サブディレクトリも含めて一覧表示した場合。
実行結果をそのまま出力してもリスト化できますが少々見ずらいので、シェルスクリプトで出力結果を整形して見やすい形で出力することを目的としてます。

1.2.使用するlsコマンド

スクリプト内で実行する「lsコマンド」の形式は以下となります。

ls -l -R --time-style=+'%Y/%m/%d %H:%M:%S' ${対象ディレクトリ}


使用しているオプションの説明

オプション内容
-l詳細表示
-Rディレクトリ内容を再帰的に表示
–time-style=+’%Y/%m/%d %H:%M:%S’タイムスタンプの書式を指定
指定書式「YYYY/mm/dd HH:MM:SS」
出力例)「2021/09/17 22:22:38」

1.3.編集内容

今回は下記のようなディレクトリに対し、サブディレクトリも含めてlsコマンドを実行する場合を例とします。
/mnt/c/RfromL_com/prod/SpaceTrim/
 ├ input/
 │└ TRIM_IN.csv
 ├ output/
 │├ TRIM_OUT.csv
 │└ TRIM_OUT_Literal.csv
 ├ SpaceTrim.bat
 ├ SpaceTrim.vbs
 └ SpaceTrim_Literal.bat

スクリプト内で実行するlsコマンドの結果をそのまま出力すると以下の形式で表示されます。

$ ls -l -R --time-style=+'%Y/%m/%d %H:%M:%S' /mnt/c/RfromL_com/prod/SpaceTrim
/mnt/c/RfromL_com/prod/SpaceTrim:
total 4
-rwxrwxrwx 1 root root 1874 2021/09/22 19:02:38 SpaceTrim.bat
-rwxrwxrwx 1 root root 3874 2021/09/19 01:56:01 SpaceTrim.vbs
-rwxrwxrwx 1 root root 1217 2021/09/27 14:36:45 SpaceTrim_Literal.bat
drwxrwxrwx 1 root root 4096 2021/09/22 20:50:16 input
drwxrwxrwx 1 root root 4096 2021/09/22 21:23:05 output

/mnt/c/RfromL_com/prod/SpaceTrim/input:
total 0
-rwxrwxrwx 1 root root 516 2021/09/07 15:31:40 TRIM_IN.csv

/mnt/c/RfromL_com/prod/SpaceTrim/output:
total 0
-rwxrwxrwx 1 root root 422 2021/09/22 00:48:39 TRIM_OUT.csv
-rwxrwxrwx 1 root root 422 2021/09/27 14:36:54 TRIM_OUT_Literal.csv


上記の出力をスクリプト内で整形し、以下のように出力します。
※タブ区切りのcsv形式で出力

パスファイル/
ディレクトリ
パーミッションサイズタイムスタンプ
/mnt/c/RfromL_com/prod/SpaceTrimSpaceTrim.bat-rwxrwxrwx18742021/09/22 19:02:38
/mnt/c/RfromL_com/prod/SpaceTrimSpaceTrim.vbs-rwxrwxrwx38742021/09/19 01:56:01
/mnt/c/RfromL_com/prod/SpaceTrimSpaceTrim_Literal.bat-rwxrwxrwx12172021/09/27 14:36:45
/mnt/c/RfromL_com/prod/SpaceTriminputdrwxrwxrwx40962021/09/22 20:50:16
/mnt/c/RfromL_com/prod/SpaceTrimoutputdrwxrwxrwx40962021/09/22 21:23:05
/mnt/c/RfromL_com/prod/SpaceTrim/inputTRIM_IN.csv-rwxrwxrwx5162021/09/07 15:31:40
/mnt/c/RfromL_com/prod/SpaceTrim/outputTRIM_OUT.csv-rwxrwxrwx4222021/09/22 00:48:39
/mnt/c/RfromL_com/prod/SpaceTrim/outputTRIM_OUT_Literal.csv-rwxrwxrwx4222021/09/27 14:36:54

1.4.実行環境

この投稿を書くにあたっての実行環境です。

マシンOS:Windows10 pro 64bit版

バージョン21H1
OSビルド19043.1237


Linux 用 Windows サブシステム(旧表記:Windows Subsystem for Linux ※WSL)

DescriptionUbuntu 20.04.3 LTS
Release20.04

2.スクリプト内容

2.1.処理内容

①引数に指定したパスディレクトリからサブディレクトリ配下のファイルも含めて一覧出力
②出力内容のタイムスタンプ項目をyyyy/mm/dd HH:MM:SS 形式で表示するよう指定
③先頭行にヘッダー行を追加
④lsコマンドの出力結果から「total」行などの不要な情報を除外
⑤出力結果をヘッダー行の項目に合わせて列を並べ替え
⑤各列をタブ区切りで出力

2.2.実行形式

$lscsv.sh 実行引数「調査対象ディレクトリパス(※)」

※)制約次項として、実行引数に指定する「調査対象ディレクトリパス」はフルパスを指定する必要があります。

2.3.コード内容

下記コード内容のシェルスクリプトファイルを作成します。
基本的な事ではありますが作成に際しては文字コード、改行コードに注意してください。
今回は実行環境(Ubuntu)に合わせて文字コード「UTF-8」、改行コード「LF」でファイルを作成しました。

シェルID:lscsv.sh

#!/usr/bin/sh
# ファイル一覧を取得したいディレクトリのパスを取得
if [ "$1" != "" ]
then
  # 引数が指定されていた場合、引数からパスを取得
  LSDIR=$1

else
  #引数の指定が無い場合、カレントディレクトリのパスを取得
  LSDIR=`pwd`
fi

# 実行シェルのパスを取得
cd `dirname $0`
OUTDIR=`pwd`

echo "以下のディレクトリ配下からファイル一覧を取得します。"
echo ${LSDIR}
echo " "

# ワーク変数
WK1=''

# 出力ファイル名設定
LIST="LIST_`date +'%Y%m%d_%H%M%S'`.txt"

# ヘッダー出力
echo "パス"'\t'"ファイル名"'\t'"パーミッション"'\t'"サイズ"'\t'"タイムスタンプ" >>${OUTDIR}/${LIST}

ls -l -R --time-style=+'%Y/%m/%d %H:%M:%S' ${LSDIR} |
while read a b c d e f g h
  do
    # "total" の行は出力対象外
    if [ "$a" != "total" ]; then

      if [ "$a" != "" ]; then

        # 1文字目を取得
        WK1=`echo $a | cut -c 1`

        if [ "${WK1}" = "/" ]; then

          # 1文字目が"/"(スラッシュ)の場合は、パスとして取得
          FILE_PATH=${a%?}

        else
          # ls の結果から必要な列のみ表示
          echo "${FILE_PATH}"'\t'"$h"'\t'"$a"'\t'"$e"'\t'"$f"' '"$g" >>${OUTDIR}/${LIST}

        fi
      fi
    fi
done

# 終了メッセージ
echo "処理結果を以下のファイルに出力しました。"
echo ${OUTDIR}/${LIST}
echo " "


3.実行方法

①シェル実行
Ubuntuのコマンドラインを起動して「cd」コマンドでシェルスクリプトの格納されている場所に移動します。

cd /mnt/c/RfromL_com/prod_sh


今回は作成したシェルスクリプトを「c:\RfromL_com/prod_sh」フォルダ配下に格納しているので以下コマンドを実行します。


ディレクトリを移動できたら、以下の通りシェルスクリプトに実行引数を指定して実行します。

./lscsv.sh /mnt/c/RfromL_com/prod/SpaceTrim

※本投稿ではubuntuのターミナルで実行しています。


②実行結果
シェル実行後、処理が終了すると下記のメッセージが表示されます。



③実行結果のファイル出力を確認
シェルの実行結果としてコマンドライン上に表示されている出力ファイルのフルパス「/mnt/c/RfromL_com/prod_sh/LIST_20210929_182056.txt」をコピーして、以下の「ls」コマンドでファイルが出力されていることを確認します。

ls -l /mnt/c/RfromL_com/prod_sh/LIST_20210929_182056.txt



④ファイルの内容を確認
出力ファイルをテキストエディタで開いて「ls」コマンドの結果が出力されている事を確認します。
ここではタブ区切りで出力されていることが視覚的に分かるようにする為、サクラエディタで開いています。


4.出力結果の使用方法

出力したファイルはエクセルに張り付けてリスト資料にすることが多かったので、出力結果の使用方法として、ファイルからのリスト資料作成の手順を記載します。


①エクセルファイルを新規で作成して開きます。



②シート内を全選択します。
「CTRL」キー + 「A」キー を押して全選択します。



③書式を変更します。
1.シート全選択したままの状態で「CTRL」キー + 「!」キー(あるいは「1」キー)を押して「セルの書式設定」ウィンドウを開きます。
2.ウィンドウが開いたら「表示形式」タブを選択、分類(C:)の中から「文字列」を選択して「OK」ボタンをクリックします。



④スクリプトの出力ファイルの内容をコピーします。
1.ファイルをテキストエディタで開き「CTRL」キー + 「A」キーを押して全選択します。
2.「CTRL」キー + 「C」キー でファイルの内容をコピーします。



⑤書式変更したエクセルに貼り付けます。
1.エクセルの貼り付けたい箇所のセルを選択します。
2.「CTRL」キー +「V」キー で データを貼り付けます。
※タブ区切りになっているので、張り付けるだけでセル毎に値がコピーされます。


⑥セル幅を変更します。
1.エクセルシートの左上隅をクリックして、シート内を全選択します。
2.A列、B列などの、列の間をダブルクリックしてセル幅を自動変更します。


⑦罫線を描画します。
データのあるセルにカーソルをあてて、「CTRL」キー + 「A」キー でデータのあるセルを選択状態にします。



「CTRL」キー + 「!」キー(あるいは「1」キー)を押して「セルの書式設定」ウィンドウを開きます。




1.「罫線」タブを選択
2.「ALT」キー+「O」(オー)キーを押下 で外線を描画
3.「ALT」キー+「I」(アイ)キーを押下 で内線を描画
4.「Enter」キーを押下



これで選択範囲内で罫線が描画されます。



⑧フィルターの設定
データのあるセルを選択した状態で「CTRL」+「Shift」+「L」キーを押下してフィルターを設定しておきます。

完成です!!


5.おわりに

今回のシェルスクリプトは端的に言うと、lsコマンドを実行して結果をファイルに出力するだけの処理です。
ですので、調査対象ディレクトリの配下にあるファイル・サブディレクトリが少なければ普通にlsコマンド(状況に応じてオプション指定)を実行するだけでもそんなに手間ではありません。

ただ、システム開発の現場では、大量のファイル・ディレクトリ、深い階層などはざらにあることです。
そんな状況で、要らなくなったファイルがそのまま放置されている事が少なくないので、消して良いファイル(要らないファイル)がないか確認する時にリストを出したりします。
そういった時に今回のシェルスクリプトを使用することで、少しは手間が減らせるんじゃないかなぁと思います。

また、今回のシェルスクリプトで作成したエクセルリストはディレクトリ・ファイル両方だしていますが、エクセルリストに設定したフィルター機能で「パーミッション」列に対してディレクトリのパーミッションを除外するフィルタリングをすればファイルだけの一覧にもできます。


実際にフィルタリングした結果が下図の状態です。


最後に。
今回のスクリプト。結構雑な作りなので、もっと良いやり方があるかもしれません。
最初はワンライナーで出来ないかなとか考えたけど、ぱっと思いつかなかったのでこんなスクリプトになりました。

まぁこれが”IT作業員”クオリティ!

ということで、おおめに見てください。

以上です。
宜しくお願い致します。