作曲・浄書・指導・音響

金沢音楽制作

金沢音楽制作では、楽曲・楽譜の制作と、作曲や写譜などレッスンを行っています。

Bashのファイル操作

Bashの操作についてのメモです。最終更新日:2019年10月15日

ファイルをコピーして連番をつける

ブレース展開を利用する。

$ ls
hoge.txt
$ for i in {1..10}; do cp hoge.txt hoge_$i.txt; done
$ ls
hoge_10.txt hoge_2.txt hoge_4.txt hoge_6.txt hoge_8.txt
hoge_1.txt  hoge_3.txt hoge_5.txt hoge_7.txt hoge_9.txt

[目次へ]

ファイル名を一括で置換する

下に色々と書いたが、sedで加工してbashに渡す方が汎用性が高く、また簡単である。

$ ls | sed -n 's/\(\(.*\)-min\(\..*\)\)/mv \1 \t \2\3/p'
mv blue-min.png      blue.png
mv delek-min.png     delek.png
mv evening-min.png   evening.png
mv murphy-min.png    murphy.png
mv darkblue-min.png  darkblue.png
mv desert-2-min.png  desert-2.png
mv industry-min.png  industry.png
mv pablo-2-min.png   pablo-2.png

上掲のsedは、mvに続く引数を作り出すものだ。/mv に続く部分がそうである。この表示で問題なければ、パイプでbashに渡す。

$ ls | sed -n 's/\(\(.*\)-min\(\..*\)\)/mv \1 \t \2\3/p' | bash
$ ls 
blue.png
delek.png
evening.png
murphy.png
darkblue.png
desert-2.png
industry.png
pablo-2.png

制御文字\t(タブ)は見やすくするために入れただけなので、なくても良い。また、マッチした行を抽出-n 's///p'もls | grep | sed ' s///'としてもよい。


下掲のファイル名に付けられている「-min」を一括で削除したい。方法として「-min」を置換で削除してしまう考え方が一般的だろう。具体的には、renameを使う、パイプを使う、そしてシェルスクリプトを使う方法がある。順に見ていこう。

$ ls
blue-min.png      delek-min.png      evening-min.png    murphy-min.png
darkblue-min.png  desert-2-min.png   industry-min.png   pablo-2-min.png

renameコマンドを使う

renameを使う。renameは非常に便利なコマンドである。使い方は、第一引数にsedの置換を、第二引数に対象ファイルを記述するだけである。renameはディレクトリも対象なので、ファイルのみの場合は対象ファイルに拡張子を含めるといった、何かしらの対策が必要である。今回の場合は、ワイルドカード展開を使って、拡張子.pngがついたファイルを対象としている。つまり、カレントディレクトリの全てのファイルの中から拡張子がpngのものだけを対象としている。なお、macOSには現在のところrenameコマンドが標準で用意されていないので、次で紹介するsedを使うか、事前にbrew等でインストールしておく必要がある。

$ rename 's/-min//' *.png
$ ls
blue.png      delek-2.png   elflord-2.png  koehler-2.png  pablo-2.png
darkblue.png  delek.png     elflord.png    koehler.png    pablo.png

パイプを使う

パイプ(|)を使って、プロセスをプロセスに渡すことで一括する。Mac等でrenameコマンドがない場合はこちらを使うことになる。しかし、これこそがUnixらしい使い方であり、必須の技術といえる。

$ ls | sed 'p; s/-min//' | xargs -n 2 mv
blue.png      delek-2.png   elflord-2.png  koehler-2.png  pablo-2.png
darkblue.png  delek.png     elflord.png    koehler.png    pablo.png

一つずつ処理を見ていこう。まず、lsして、ファイルの一覧を取得する。

$ ls
blue-min.png      delek-min.png      evening-min.png    murphy-min.png
darkblue-min.png  desert-2-min.png   industry-min.png   pablo-2-min.png

次に、それをパイプでsedに渡し、引数に'p; s/-min//'と記述する。この引数について説明する。''内においてpとsが;で区切られているが、これは、複数の処理を記述する場合の区切りである。つまり、二つの処理が成されているのである。まず、pはプリント、つまりsedが受け取った内容をそのまま画面に表示することだ。そして次の処理として置換が行われるのである。これを実行すると、「-min」がついたファイルと削除されたファイルが交互に表示されることが分かる。ここまでくればあと一息である。

$ ls
blue-min.png
blue.png
delek-min.png
delek.png
evening-min.png
evening.png
murphy-min.png
murphy.png
darkblue-min.png
darkblue.png
desert-2-min.png
desert-2.png
industry-min.png
industry.png
pablo-2-min.png
pablo-2.png

そして登場するのがxargsというちょっと複雑なコマンドである。xargsを端的に説明すると、パイプで受け取った内容を、引数で指定したコマンド(この場合はmv)の引数にする、というものである。今回の「xargs -n 2 mv」を詳細に見よう。xargsは説明したとおりであるが、その引数に「-n 2 mv」と記述してある。「-n 」は実行するコマンドに渡す引数の数を指定するオプションで、次の「2」がその数である。つまり、二つの引数がmvに渡されるのである。これを視覚的に表現するならば次のコマンドと同じである。

$ mv blue-min.png blue.png

シェルスクリプトを作成する

最後は、シェルスクリプトにしてしまう方法である。かなりの力技だが、手順は簡単である。まず、リダイレクトを使ってlsの結果をファイルにわたす。次に、エディタでそれを開く。そして、mvを使ったコマンドを大量に書き、bashにわたして実行する。作成が少し面倒くさいが、エディタの機能を使えば比較的に簡単に作成できると思う。

$ ls > rename.sh
$ vi !$
$ cat !$
mv blue-min.png blue.png
mv delek-min.png delek.png
mv evening-min.png evening.png
mv murphy-min.png murphy.png
mv darkblue-min.png darkblue.png
mv desert-2-min.png desert-2.png
mv industry-min.png industry.png
mv pablo-2-min.png pablo-2.png
$ bash !$
$ ls
blue.png
delek.png
evening.png
murphy.png
arkblue.png
desert-2.png
industry.png
pablo-2.png 

「!$」には、直前のコマンドの最後の引数が格納されている。今回なら、rename.shにあたる。

[目次へ]

lsの結果からディレクリだけを、あるいは通常ファイルだけを取得する

下に色々と書いたが、lsとgrepだけで目的は達成できる。lsの引数に-Fをつけると、ファイル名の末尾にタイプが表示される。ディレクトリならば「/」、実行ファイルならば「*」、シンボリックリンクならば「@」、そして末尾になにもつかない物が通常ファイルだ。あとはこの結果をgrepにわたすだけである。

$ ls -F
vimrc@
Desktop/
Downloads/
Dropbox/
gdrive-beta.sh*
hkmc.jp_bk
n49.html
n50.html
note/
works/

grepは、マッチしたパターンを除外する-vオプションの利用がこつとなる。例えば、通常ファイルのみ表示させたい場合は、ファイルの末尾につけられた「/*@」の記号をマッチさせ、それを除外させればよい。

$ ls -F | grep -v'[/*@]$'
hkmc.jp_bk
n49.html
n50.html

ここではlsとsed、awkをパイプライン(|)でつなぐ方法を示す。

$ ls -l
total 44
drwxr-xr-x  3 hase hase 4096 Nov 15 16:37 Desktop
drwxr-xr-x  5 hase hase 4096 Nov 15 20:14 Downloads
drwx------ 13 hase hase 4096 Oct  2 15:06 Dropbox
-rwxr-xr-x  1 hase hase 5573 Nov 15 16:10 gdrive-beta.sh
drwxr-xr-x 13 hase hase 4096 Nov  3 15:42 hkmc.jp_bk
-rwxr-xr-x  1 hase hase 3357 Nov 17 00:38 n49.html
-rwxr-xr-x  1 hase hase 5981 Nov 17 00:38 n50.html
drwxr-xr-x  3 hase hase 4096 Nov 17 16:12 note
drwxr-xr-x  7 hase hase 4096 Nov  9 22:38 works

ls -lを実行すると、第1:フィールド(先頭)にファイル属性が表示される。drwxr-xr-xの先頭の一文字が形式を表している。「-」ならばファイル、「d」ならばディレクトリ、「l」ならばリンクだ。

$ ls -l | sed -n  '/^d/s/.* \(.*\)/\1/p'
$ ls -l | sed -n '/^d/s/.* //p'
$ ls -l | sed -n 's/^d.* //p'

sedを利用する場合は、先頭がd(^d)で始まる行を対象として、最後の半角スペースまでの文字列(.* )を選択し置換する。そして指定した行(-n)だけプリントする(p)。

$ ls -l | awk '/^d/ {print $9}'

awkを利用する場合は、先頭がd(^d)で始まる行を対象として、第9フィールド($9)を抽出する。

[目次へ]