Bashプログラミング
 Computer >> コンピューター >  >> プログラミング >> Bashプログラミング

Bashとシェルの展開機能で実現する「怠惰な」リスト作成術

またこの季節がやってきました!お店にカラフルでキラキラ光るプラスチックの飾りが並び始めると、誰もが少し浮かれた気分になります。つまり、ショッピングに出かけましょう、ということです。そう、ホリデーシーズンのプレゼント選びです!(自分への贈り物も、厳密には立派な贈り物の一種ですからね。)

買い物が完全に暴走しないように、プレゼントのリストをいくつか作っておきましょう。Bashがその手助けをしてくれます。

ブレース展開

これらはブレース(波括弧)ではありません:()

これらでもありません:[]

これこそがブレースです:{}

ブレースは、その間に見つけた任意の文字列に対して何らかの処理を行うようBashに指示します。複数の文字列はカンマで区切って指定します({a,b,c})。また、展開された各結果の前後に付ける接頭辞や接尾辞を追加することもできます。主に、よく使うファイルパスや拡張子などの入力の手間を省くのに役立ちます。

プレゼントを贈りたい相手ごとにリストを作りましょう。以下のコマンドはすべて同じ結果になります:

touch /home/me/gift-lists/Amy.txt /home/me/gift-lists/Bryan.txt /home/me/gift-lists/Charlie.txt
touch /home/me/gift-lists/{Amy,Bryan,Charlie}.txt
tree gift-lists

/home/me/gift-lists
├── Amy.txt
├── Bryan.txt
└── Charlie.txt

あらら、「Bryan」さんは名前を「i」を使って「Brian」と綴るんでした。修正しましょう。

mv /home/me/gift-lists/{Bryan,Brian}.txt

renamed '/home/me/gift-lists/Bryan.txt' -> '/home/me/gift-lists/Brian.txt'

シェルパラメータ展開

シェルパラメータ展開を使うと、ブレースで囲まれたパラメータに対して、テキストの操作や置換など、さまざまな変更を加えられます。

プレゼントをもらう全員に配るべき「靴下の中の小物」があります。変数にしてみましょう:

STUFF=$'socks\nlump of coal\nwhite chocolate'

echo "$STUFF"
socks
lump of coal
white chocolate

次に、teeコマンドの力を借りてechoと展開をうまく連携させ、これらのアイテムをそれぞれのリストに追加します。

echo "$STUFF" | tee {Amy,Brian,Charlie}.txt

cat {Amy,Brian,Charlie}.txt

socks
lump of coal
white chocolate
socks
lump of coal
white chocolate
socks
lump of coal
white chocolate

パターンマッチによる置換

よく考えてみると、石炭の塊(lump of coal)はあまり良い贈り物ではなさそうです。${parameter/pattern/string}という形式のパターンマッチ置換を使えば、もっと良いものに差し替えられます:

echo "${STUFF/lump of coal/candy cane}" | tee {Amy,Brian,Charlie}.txt

cat {Amy,Brian,Charlie}.txt

socks
candy cane
white chocolate
socks
candy cane
white chocolate
socks
candy cane
white chocolate

これは最初に見つかった「lump of coal」を「candy cane」に置き換えます。すべての出現箇所を置き換えたい場合(複数ある場合)は、${parameter//pattern/string}を使用します。この操作では$STUFF変数自体は変更されないため、元のリストは後で「悪い子」向けに再利用できます。

部分文字列

改善を続けましょう。ホワイトチョコレートが苦手な人もいるかもしれません。念のため普通のチョコレートもリストに追加しておいたほうがよさそうです。私はとても怠惰なので、上矢印キーを押して以前のBashコマンドを呼び出して修正することにします。幸い、$STUFF変数の最後の単語は「chocolate」で、ちょうど9文字です。${parameter:offset}を使って、その部分だけを取り出すようBashに指示します。既存のリストに追記するため、tee-a(append)フラグも併用します:

echo "${STUFF: -9}" | tee -a {Amy,Brian,Charlie}.txt

cat {Amy,Brian,Charlie}.txt

socks
candy cane
white chocolate
chocolate
socks
candy cane
white chocolate
chocolate
socks
candy cane
white chocolate
chocolate

次のような指定も可能です:

やりたいこと 使う構文
n文字目以降の部分文字列を取得 ${parameter:n}
n文字目からx文字分の部分文字列を取得 ${parameter:n:x}

これで基本のリストが完成しました。エッグノグでも一杯飲みましょう。

変数のテスト

エッグノグのせいかどうかわかりませんが、昨日Amy用のリストを作り始めて、amyという名前の変数に保存したような気がします。確認してみましょう。${parameter:?word}という展開を使います。これは、amyパラメータが存在しない場合にwordを標準エラー出力に書き出して終了します。

echo "${amy:?no such}"

bash: amy: no such

やっぱりなかったようです。Brianだったかもしれません。

echo "${brian:?no such}"

Lederhosen

次のようなバリエーションもあります:

やりたいこと 使う構文
parameterが未設定またはnullの場合にwordを代替値として使用 ${parameter:-word}
parameterが未設定またはnullでない場合にwordを代替値として使用 ${parameter:+word}
parameterが未設定またはnullの場合にparameterへwordを代入 ${parameter:=word}

大文字・小文字の変換

そうでした!Brianはレーダーホーゼン(Lederhosen)が欲しいと言っていたので、自分用のメモを作ったのでした。これはかなり重要な情報なので、${parameter^^pattern}という展開を使って、すべて大文字でBrianのリストに追加しましょう。patternの部分は省略可能です。Brianのリストだけに書き込むので、今回はtee -aの代わりに>>を使います。

echo "${brian^^}" >> Brian.txt

cat Brian.txt

socks
candy cane
white chocolate
chocolate
LEDERHOSEN

次のようなバリエーションもあります:

やりたいこと 使う構文
最初の1文字だけを大文字化 ${parameter^pattern}
最初の1文字だけを小文字化 ${parameter,pattern}
すべての文字を小文字化 ${parameter,,pattern}

配列の展開

正直なところ、プレゼントリストの管理はかなり骨が折れます。店で見かけた品物をまとめて配列にしてしまいましょう:

gifts=(sweater gameboy wagon pillows chestnuts hairbrush)

${parameter:offset:length}という形式の部分文字列展開を使えば、シンプルに処理できます。最初の2つはAmyのリストへ、真ん中の2つはBrianのリストへ、最後の2つはCharlieのリストへ追加します。改行の整形にはprintfを使います。

printf '%s\n' "${gifts[@]:0:2}" >> Amy.txt
printf '%s\n' "${gifts[@]:2:2}" >> Brian.txt
printf '%s\n' "${gifts[@]: -2}" >> Charlie.txt
cat Amy.txt

socks
candy cane
white chocolate
chocolate
sweater
gameboy

cat Brian.txt

socks
candy cane
white chocolate
chocolate
LEDERHOSEN
wagon
pillows

cat Charlie.txt

socks
candy cane
white chocolate
chocolate
chestnuts
hairbrush

これで完成です!一人ひとりの好みに合わせた、充実のプレゼントリスト一式ができあがりました。ありがとう、Bash!残念ながら、実際の買い物までは代行してくれませんが。

  1. Bashの特殊変数「$$」と「$BASHPID」の違いを徹底解説

    シェルスクリプトの作業中に、Bashの特殊変数 $$ と $BASHPID の間に大きな動作の違いがあることに気づきました。Linux上で実行されるすべてのプロセスにはプロセスID(PID)が割り当てられ、OSはこのIDをもとにプロセスを管理しています。 関連記事: Bashにおけるソース読み込み(source)とフォーク(fork)の違いを学ぶ 同様に、あなたが開いているBashターミナルのセッションにもプロセスIDが割り当てられます。そして、現在のシェルのプロセスIDを格納する特別な変数として $$ と $BASHPID の2つが用意されています。 現在のシェルのPIDを確認する まずは以

  2. jm-shell – 情報量豊富で自由にカスタマイズできるBashシェル

    jm-shellとは jm-shellは、無料で利用できるオープンソースの軽量Bashシェルです。シェル上での操作に関する豊富な情報をリアルタイムに表示するだけでなく、システムの負荷平均やノートパソコンのバッテリー状態など、実用的なシステム情報もひと目で確認できます。 特筆すべき点として、通常のBashが重複を除いたコマンドのみを履歴ファイルに保存するのに対し、jm-shellはすべてのシェル操作をログファイルに記録します。これにより、過去に実行したコマンドを後から確実に検索・確認できます。 さらに、現在のディレクトリがGit、Subversion、Mercurialなどのバージョン管理システ