20200602のLinuxに関する記事は14件です。

Lubuntu 18.04で、ゴミ箱が使えないときの対処法。

数ヶ月前に、私はWindowsをきっぱりやめて、Lubuntu 18.04に移行したのであるが、そのとき、何故かゴミ箱が使えなかったので、当時の対処法をここに記述する。

現象

ファイルをゴミ箱に移動しようとすると、何故かエラーが出て(肝心のエラーの内容をメモするのを忘れてしまった。)ゴミ箱にファイルを移動できない現象であった。

至って簡単だった対処法

対処法は至って簡単だったのである。それは、rootでゴミ箱フォルダを消して、通常の権限でゴミ箱フォルダを再度作成するというものである。

root権限で、ファイルマネージャーを開く

通常、ゴミ箱のディレクトリは、"~/.local/share" にあるため、そこをまずは開く。Lubuntuの場合、標準のファイルマネージャはPCManFMであるため、以下のようにすればよいだろう。

sudo pcmanfm ~/.local/share

Trashフォルダを削除する。

そこには、「Trash」フォルダがある。それが問題のゴミ箱フォルダである。そのフォルダを削除する。このとき、ゴミ箱は正常に機能していないため、Shiftキーを押しながら、Deleteキーを押すことで、完全に削除できるため、この方法で完全削除する。

Trashフォルダーを作り直す。

今度は、通常の権限で "~/.local/share" ディレクトリに移動する。
移動できたら、そこに「Trash」という名前のフォルダを作成する。これで終わり。

動作するか試す。

一応一旦ログアウトし、再度ログインして、適当なファイルをゴミ箱に入れてみよう。正常に動いていれば、そこにデータがあり、ゴミ箱も空にできるはずだ。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linux : topコマンドで表示される情報を理解する

はじめに

会社の研修中にtopコマンドで実行中のプロセス一覧が見れることを教わりました。教わったことと調べたことを整理しつつ、topコマンドで表示される情報を理解するのが本記事の目的です。

こちらの記事を参考にしました

https://qiita.com/k0kubun/items/7368c323d90f24a00c2f

topコマンドとは

topコマンドは、そのシステムで実行されているプロセスの一覧を表示するlinuxコマンドです。システム全体の負荷や、プロセスごとのメモリ使用量などを見ることができます。

topコマンドを実行してみる

topコマンドを実行するとシステムのプロセス情報が一度に表示されます。
Screenshot from 2020-06-02 19-31-18.png
初心者目には情報が多いですが、少しづつ見ていきます。

ヘッダー部分

画像での空行を区切りとして、そこから上部の部分をヘッダー部分として見ていきます。

時間とユーザー数

top - 19:41:02 up  3:35,  1 user,  

一行目「top」と書かれている箇所の情報です。
左から

  • 現在時間
  • サーバーの稼働時間(「up 3:35」の部分。「時:分」表記)
  • ログインユーザー数

となります。

load average

load average: 0.52, 0.44, 0.53

一行目残りの部分の情報です。
この欄には、単位時間あたりの平均待ちタスク(プロセス)数が表示されています。小数が3つ並んでいますが、左から直近で「1分, 5分, 15分」間の単位時間あたり待ちタスク数となっています。
上の画像だと例えば、直近1分間の平均待ちタスク数は0.52タスク、ということになります。

Tasks

Tasks: 387 total,   1 running, 315 sleeping,   0 stopped,   0 zombie

現在のタスクを状態ごとに見ることができます。

  • total : 全タスク数
  • running : 稼働中タスク数
  • sleeping : 待機中タスク数
  • stopped : 停止したタスク数
  • zombie : ゾンビタスク数

CPU

%Cpu(s):  2.9 us,  0.3 sy,  0.0 ni, 96.6 id,  0.0 wa,  0.0 hi,  0.2 si,  0.0 st

CPUの利用時間の割合をプロセスの種類ごとに見ることができます。上の画像では単位がありませんが、単位は「%」です。

  • us : userプロセス
  • sy : systemプロセス
  • ni : niceプロセス
  • id : idleプロセス
  • wa : I/O waitプロセス
  • hi : hardware interruptプロセス(interruptは「割り込み」という意味です)
  • si : software interruptプロセス

(個々のプロセスがどういうプロセスなのかは他の機会に調べようと思います。)
画面で「1」を押すと、個々のCPUごとの情報に切り替えることができます。

%Cpu0  :  1.0 us,  0.0 sy,  0.0 ni, 98.3 id,  0.0 wa,  0.0 hi,  0.7 si,  0.0 st
%Cpu1  :  0.7 us,  0.0 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  1.4 us,  0.3 sy,  0.0 ni, 98.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.4 us,  0.7 sy,  0.0 ni, 98.9 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu4  :  0.7 us,  0.3 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu5  :  1.0 us,  0.7 sy,  0.0 ni, 98.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu6  :  0.3 us,  0.0 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu7  :  0.3 us,  0.0 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st

Memory/Swap

KiB Mem :  7965864 total,   336044 free,  5603244 used,  2026576 buff/cache
KiB Swap:  2097148 total,  1692156 free,   404992 used.   800580 avail Mem 

物理メモリとスワップ領域の使用メモリ量が表示されています。「Mem」が物理領域、「Swap」がスワップ領域です。
スワップ領域についてはこちらのサイトがわかりやすかったです。

  • total : 全メモリ量
  • free : 使用していないメモリ量
  • used : 使用中のメモリ量
  • buff/cache : バッファ/キャッシュで使用されているメモリ量

最後の「avail Mem」は「新しいアプリがスワップせずに使えるメモリ量」です。

プロセス一覧部分

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                                                                 
 1407 sada      20   0  604828  92172  63112 S   2.0  1.2   6:17.70 Xorg                                                                                                                                    
 2196 sada      20   0 7374224 476924  53408 S   1.7  6.0   8:05.10 java                                                                                                                                    
 1537 sada      20   0 4039788 274080 115156 S   1.3  3.4   8:13.99 gnome-shell                                                                                                                             
 2768 sada      20   0 2008760 555128 310552 S   1.0  7.0   7:52.98 chrome                                                                                                                                  
12359 sada      20   0  849556  48752  34872 S   1.0  0.6   0:07.22 gnome-terminal- 

空行より下の部分には実行中のプロセス一覧が表示されます。

  • PID : プロセスID
  • USER : そのプロセスを実行しているユーザー
  • PR : 優先度 0を基準とした、相対的な優先度です。負の値もあります。
  • VIRT : 確保されている仮想メモリ量
  • RES : 使用している物理メモリ量
  • SHR : 他のプロセスと共有される可能性のあるメモリ量
  • S : プロセスのステータス アルファベットによって分類されています
    • D: 割り込み不能押すと
    • R: 実行中
    • S: スリープ状態
    • T: 停止中
    • Z: ゾンビプロセス
  • %CPU : CPUの使用率
  • %MEM : メモリの使用率
  • TIME+ : プロセスの実行時間
  • COMMAND : プロセスの実行コマンド名

このプロセス一覧では、「Shift + p」でCPU使用率順(%CPU)、「Shift + m」でメモリ使用率順(%MEM)に並べ替えることができます。
また画面上で「c」を押すと「COMMAND」の部分が絶対パスで表示されます。

メモリ使用率順で並び替えて、絶対パスを表示した画像がこちらです。
Screenshot from 2020-06-02 20-51-59.png

さいごに

topコマンドで表示されるプロセス一覧画面の見方をまとめました。
topコマンドには他にも便利な機能がたくさんあるようです。使いこなして、プロセス管理をスムーズに行っていきたいです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

シェルスクリプトでファイルの中身を順に処理

1.やりたいこと
2.コード紹介
3.実行例

やりたいこと

ファイルの中身を取得して上から順番に処理していきます。
本記事ではファイル内の名前データ(name.txt)の中身を上から取得して、通し番号をつけてcsv(name.csv)に変換するループ文のシェルスクリプトを紹介します。

コード紹介

現在のフォルダの状況

実行前の状態
$ cat name.txt
Taro Suzuki
Jiro Suzuki
Noriko Yamada
Junko Nishida
main.sh
#!/bin/sh
cnt=1

cat name.txt | while read data
do
    echo ${cnt},${data} >> name.csv
    #cnt変数のインクリメント
    cnt=`expr ${cnt} + 1`
done

実行例

main.shの実行
sh main.sh
実行後の状況
$ cat name.csv
1,Taro Suzuki
2,Jiro Suzuki
3,Noriko Yamada
4,Junko Nishida
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

シェルスクリプトでフォルダ内のファイルを順番に処理

1.やりたいこと
2.コード紹介
2.実行例
2.おまけ

やりたいこと

フォルダ内のデータ(名前)を取得します。
本記事ではフォルダ内ファイルの拡張子を.txtから.logに変更するループ文のシェルスクリプトを紹介します。

コード紹介

現在のフォルダの状況

実行前の状況
$ ls
1.txt   2.txt   3.txt   4.txt   5.txt   main.sh
main.sh
#!/bin/sh
for filename in *.txt; 
do
    mv ${filename} ${filename%.txt}.log;
done

実行例

main.shの実行
sh main.sh
実行後の状況
$ ls
1.log   2.log   3.log   4.log   5.log   main.sh

.txt拡張子が.logに変更されていることがわかります。

おまけ

何十万のデータに番号をつけたい場合も利用できますね。
for分の途中でカウンタを文字列付与すれば一気に大量のデータに番号をつけることもできます。

main.sh
#!/bin/sh
cnt=1
for filename in *.txt; 
do
    mv ${filename} data_${cnt}.log;
    #cnt変数のインクリメント 
    cnt=`expr ${cnt} + 1`
done
実行後の状況
$ ls
data_1.log  data_2.log  data_3.log  data_4.log  data_5.log  main.sh
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

シェルスクリプトでフォルダ内のファイルを順に処理

1.やりたいこと
2.コード紹介
3.実行例
4.おまけ

やりたいこと

フォルダ内のデータ(名前)を取得します。
本記事ではフォルダ内ファイルの拡張子を.txtから.logに変更するループ文のシェルスクリプトを紹介します。

コード紹介

現在のフォルダの状況

実行前の状況
$ ls
1.txt   2.txt   3.txt   4.txt   5.txt   main.sh
main.sh
#!/bin/sh
for filename in *.txt
do
    mv ${filename} ${filename%.txt}.log
done

実行例

main.shの実行
sh main.sh
実行後の状況
$ ls
1.log   2.log   3.log   4.log   5.log   main.sh

.txt拡張子が.logに変更されていることがわかります。

おまけ

何十万のデータに番号をつけたい場合も利用できますね。
for分の途中でカウンタを文字列付与すれば一気に大量のデータに番号をつけることもできます。

main.sh
#!/bin/sh
cnt=1
for filename in *.txt; 
do
    mv ${filename} data_${cnt}.log;
    #cnt変数のインクリメント 
    cnt=`expr ${cnt} + 1`
done
実行後の状況
$ ls
data_1.log  data_2.log  data_3.log  data_4.log  data_5.log  main.sh
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Linux基礎15 -シェルスクリプトの基礎知識-

はじめに

今回はシェルスクリプトを書くための基礎知識を紹介します。少し長くなってしまいますが、よろしくお願いいたします。

シェルスクリプトの基本

シェルスクリプトを書く上で、最も基本となる、行の見方や、コメントについて紹介します。

シェルスクリプトの行

シェルスクリプトでは、実行したいコマンドラインをファイルに記述することでコマンドが実行されます。
次のシェルスクリプトでは、複数のコマンドを記述しています。

複数のコマンドを実行するシェルスクリプト(rootls.sh)
#!/bin/bash #シェバン

echo "root directory"
cd /
ls -l

このシェルスクリプトを実行するとルートディレクトリのファイル一覧が表示されます。
スクリーンショット 2020-06-01 14.07.23.png
また、複数のコマンドは;で区切ることで、1行にまとめて書くことができます。次の先ほどのコマンドは次のように書き換えることもできます。

;で区切ることで複数のコマンドを1行にまとめる(rootls.sh)
#!/bin/bash

echo "root directory";cd /;ls -l

なおシェルスクリプトでは、空行は無視されるため、読みやすくするために空行を入れても構いません。シェバンの後ろに1行空行を入れることで読みやすくすることが多く行われています。

複数行での記述

コマンドラインが長くなってしまう場合には、行末に\を置くことで途中で改行できます。これは見た目が改行されているだけで、シェルスクリプトとして実行される際には、次の行に連結して実行されます。

コマンドライン内での\による改行(echo_root.sh)
#!/bin/bash

echo \  #途中でechoコマンドが改行されている
"root directory"

スクリーンショット 2020-06-01 14.19.12.png
オプションや引数ををいくつも指定してコマンドラインが長くなってしまう場合には、この機能を利用するとシェルスクリプトが読みやすくなります。

なお普段のシェルでも\を利用することができます。次のようにシェルで\を入力することでプロンプトが>に変化しました。これは、コマンドラインが終了していないため、続きを入力してくださいという入力待ちの状態を意味するプロンプトです。これをセカンダリプロンプトといいます。この文字はシェル変数PS2でカスタマイズすることもできます。
スクリーンショット 2020-06-01 14.22.57.png
なお、|(パイプ)を利用して、パイプラインでコマンドラインを繋ぐ際にも、|の直後に改行を入れて、次のように記述しても構いません。

|(パイプ)による改行の例
sort file3 | #file3を行単位でASCIIコードの順に並べ替える
uniq -c |    #連続した行の重複したファイルを省略する -cで各行の前に出現回数を表示する
sort -n    #文字列を数値とみなして並べ替える

コメント

シェルスクリプトの中にはコメントを挿入することができます。コメントとは、動作に関係のない注意書きのことで、シェルスクリプトの説明を書くときに使います。
シェルスクリプトでは、#を書くとその行の終わりまでコメントとなります

コメントの挿入
#!/bin/bash

echo "root directory"

#ルートディレクトリに移動する
cd /

ls -l # ファイルサイズ、パーミッションなども合わせて表示する

# echo "current directory"

コメントは何が書かれていても無視されますので、そこにコマンドが書いてあったとしても実行されません。一時的にコマンドを実行させないためにコメント行にすることもあります。

変数

シェルスクリプトでも、通常のプログラムと同じように値を格納する変数を利用できます。これをシェル変数と呼びます。シェル変数に値を代入するには<変数名>=<値>という形式で指定します。変数の値を参照するには、変数名の前に$を付けます

変数の値を参照する(var.sh)
#!/bin/bash

appdir=/home/nossy/work
echo $appdir

スクリーンショット 2020-06-01 14.53.15.png

変数の書き方の注意

シェルスクリプトで変数を利用する際の注意点について、紹介します。

代入時には$を付けない

変数への代入時には、変数名の前に$を付けません。そのため次のように書くと、エラーになります。変数名の前に$をつけるのは、変数展開して値を参照したいときだけです。変数名に$をつけることで値を取得するというイメージを持っておくといいかもしれません。

エラーになる変数の書き方
$appdir=/home/nossy/work

=の前後にはスペースを入れない

多くのプログラミング言語では、変数に値を代入する際には=の前後にスペースを入れることができます。しかし、シェルスクリプトでは、スペースを入れることはできません。次のように=前後にスペースを入れるとエラーになります。

エラーになる書き方
appdir = /home/nossy/work

### 変数名に利用できる文字

変数名に利用できる文字は、アルファベットと数値と_(アンダースコア)だけです。また、数値は先頭の1文字目には使うことができません。そのため変数名の先頭は必ずアルファベットか_(アンダースコア)にします。

変数名の良し悪し
- 利用できる変数名      : appdir1、a13_box、_temp、OSAKA etc..
- 利用できない変数名   : 1appdir、my-app、that's etc..

なお、大文字小文字の使い分けですが、環境変数には大文字を、それ以外には小文字を使うケースが一般的です。

変数名の区切りを明示する。

変数展開した値に文字列を連結したい場合、文字列の全体が変数名の一部とみなされてしまうことがあります。例えば次のような例です。

文字列の全体が変数名とみなされる場合
#!/bin/bash

filename=my_app
echo $filename_backup #これではfilename_backupという変数であるとシェルに解釈されてしまう

上のような問題を避けるには、変数名の部分を{ }で囲んで変数名の区切りを明示してあげる必要があります。

文字列の一部の変数を明示する(sep_var.sh)
#!/bin/bash

filename=my_app
echo ${filename}_backup   #{変数名}として変数名の区切りを明示する

このシェルスクリプトを実行すると、次のようにmy_app_backupと出力されます。
スクリーンショット 2020-06-01 15.25.09.png

クォーティング

bashではコマンドの引数はスペースによって区切られます。

2つの引数を渡す場合
$ cat file1 file2

「my app」のようにスペースを含むファイル名を指定したい場合には、コマンドの引数を'(シングルクォート)や"(ダブルクォート)で囲む必要があります。これをクォーティングと言います。

スペースを含むファイル名を引数にする
$ cat 'my app' "my file"

このほかにも、シェルに解釈される特別な意味の文字(メタ文字)を利用する際にはクォーティングを用います。次の例では、*がシェルのワイルドカードと認識されないように、クォーティングしています。

ワイルドカードのクォーティング
$ grep 'Be*r' drink.txt

クォート中の変数展開

クォートには'(シングルクォート)と"(ダブルクォート)の2つがあります。この2つの違いは、$による変数展開がされるかどうかです。例をみてみましょう。

シングルクォートとダブルクォートの違い(quoto.sh)
#!/bin/bash

country=Japan
echo 'I came from $country'
echo "I came from $country"

スクリーンショット 2020-06-01 15.39.37.png

' 'の中では変数展開が無効になるため、$countryがそのまま文字列として出力されています。
一方、" "の場合は、変数展開が有効なため、Japanと出力されています。

なお、" "の中でも、$の前に(バックスラッシュ)を置いてエスケープすることで、$記号そのものを出力することができます。

$をエスケープする
echo "I came from \$country" 
#=> I came from $country

コマンド置換

シェルスクリプトでは、こまんどの出力結果をシェルスクリプト中で利用したいことがあります。このようなケースではコマンド置換という機能を利用して、コマンドの結果を文字列として取得することができます

コマンド置換$( )という形式で、カッコ内に実行したいコマンドを記述します。シェルスクリプトの実行時に$( )の部分がコマンドの標準出力で置換されます。例として、日付を出力するdateコマンドを利用してみましょう。
スクリーンショット 2020-06-01 15.58.43.png

現在日付のファイルを作成する(mkfile.sh)
#!/bin/bash

filename=$(date '+%Y-%m-%d')
touch "$filename"

上の例では、シェル変数filenameには現在の日付が代入されます。その後にtouchコマンドでファイルを作っていますので、これは現在の日付でファイルを作成するシェルスクリプトです。
スクリーンショット 2020-06-01 16.06.47.png
コマンドの置換は、"(ダブルクォート)の中でも有効です
スクリーンショット 2020-06-01 16.11.02.png
なお、コマンド置換は`(バッククォート)で囲む記法もありますが、コマンド置換内でコマンド置換を使うという入れ子構造を使用したい場合などに見辛いなどの欠点があるため、$( )を用いることが一般的です。

位置パラメータ

多くのLinuxコマンドは、コマンドライン引数によって対象ファイルなど様々な値を指定します。シェルスクリプトからコマンドライン引数を扱うには、位置パラメータと呼ばれるシェル変数を使用します。位置パラメータとは$1, $2, $3...と1から順に並んだ変数で、それぞれにシェルスクリプトを呼び出したときにコマンドライン引数が格納されています。

コマンドライン引数と位置パラメータ
$ ./parameters.sh aaa bbb ccc

./parameters => $0  #特殊パラメータ
aaa          => $1  #位置パラメータ
bbb          => $2  #位置パラメータ
ccc          => $3  #位置パラメータ

位置パラメータの利用方法を確認する例を上げてみましょう。以下のようなシェルスクリプトを作ります。

位置パラメータの利用(parameters.sh)
#!/bin/bash

echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"
echo "\$4 = $4"
echo "\$5 = $5"

コマンドライン引数を3つほど適当に与えて実行してみます。
スクリーンショット 2020-06-01 16.28.05.png
引数にワイルドカードを指定することもできます。カレントディレクトリのファイルが順番に引数に代入されてますね。
スクリーンショット 2020-06-01 16.30.13.png

引数の個数

コマンドラインに指定された引数の個数は、特殊パラメータ$#という変数で参照できます。この変数には、シェルスクリプトを実行したときの引数の個数が格納されています。前回のファイルに1行加えて実行してみましょう。

位置パラメータの利用(parameters.sh)
#!/bin/bash

echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"
echo "\$4 = $4"
echo "\$5 = $5"
echo "\$# = $#"

スクリーンショット 2020-06-01 16.34.05.png
このように、引数の個数を表示することができました。引数の指定が必要なシェルスクリプトを作るときに役立つでしょう。

引数全体の参照

位置パラメータはコマンドラインを自動的に分割しますが、逆に引数を分割せずにまとめて扱う場合には$@または$*を利用します。次のようなシェルスクリプトを用いてみていきましょう。

まとめて引数を扱うサンプル例(args.sh)
#!/bin/bash

echo "\$@ = $@"
echo "\$* = $*"

このシェルスクリプトに引数を渡して実行しましょう。
スクリーンショット 2020-06-01 16.40.31.png
一見すると、$@と$*は同じ動作のように見えますが、大きな違いがあります

$@と$*の違い
$@ = aaa bbb ccc => "$@" = "aaa" "bbb" "ccc" #""で囲むと位置パラメータがそれぞれ文字列として展開される
$* = aaa bbb ccc => "$*" = "aaa bbb ccc"   #""で囲むと引数全体が文字列として展開される

多くのケースでは引数をそれぞれ扱いため$@が多く用いられています。
次の例は、シェルスクリプト実行時の引数を、そのままコマンドに渡す例です。このような用途でかかれるシェルスクリプトをラッパー(包むもの)と呼ばれます。

ラッパー
#!bin/bash

export LANG=C         #環境変数LANGをC(英語)に指定
./some_command "$@"   #英語環境下で、引数をそのまま引き継いでコマンドを実行

コマンドライン引数に関係するシェル変数のまとめ

変数 内容
$0 実行時のシェルスクリプト名
\$1,\$2,\$3... コマンドライン引数の値(位置パラメータ)
$# 位置パラメータの個数
$@ 全ての位置パラメータ。ダブルクォートで囲むと、それぞれの位置パラメータがダブルクォートで囲まれる。
$* 全ての意図パラメータ。ダブルクォートで囲むと、全体が1つの文字列として、ダブルクォートで囲まれる。

制御構造

bashは通常のプログラム言語と同じように、値による条件分岐や、繰り返し処理を行うことができます。これを制御構造と呼び、プログラム言語において非常に重要な機能です。
ここではよく使われる例として、if, for, case, whileの複合コマンドを紹介します。

if文

if文は条件を評価して、その真偽に応じて処理を分岐するための機能を持ちます。例をみていきましょう。

if文の使用例
#!/bin/bash

if [ "$1" = "bin" ]; then #[ "$1" = "bin" ]の部分が条件判定
    echo "OK"        #条件判定が真なら実行
else
    echo "NG"        #条件判定が偽なら実行
fi

スクリーンショット 2020-06-01 19.17.58.png
なお、インデントはタブでもスペースでも構いません。インデントはスクリプトを読みやすくするものなので、省略してもエラーにはなりません。

記述上の注意点

if文を書く際の注意点についていくつか紹介します。

if文を書くときの注意点
条件を書いた後の;を省略するとエラーになる
if [ "$1" = "bin" ] then         #エラーになる
if [ "$1" = "bin" ]              #改行すればエラーにはならない
then

[ ]の前後のスペースを省略するとエラー
if[ "$1" = "bin" ]; then         #ifと[の間にスペースがない
if ["$1" = "bin" ]; then         #"[と"$1"の間にスペースがない

ifの後ろにはコマンドを書く

多くのプログラム言語では、if文に書くものは条件式となっています。しかし、シェルスクリプトではif文の後ろに書くのは「コマンド」であって、条件式ではないことに注意してください。

シェルスクリプトでのif文の書き方は次のようになります。

if文の書き方
if  <コマンド1>; then
    <コマンド1>が真である場合に実行
elsif <コマンド2>; then
    <コマンド2>が真である場合に実行
else 
    上記の結果が全て偽である場合に実行
fi

ちなみに、先ほどの例の[ ]はコマンドです。
スクリーンショット 2020-06-01 19.34.56.png

if文では、コマンドの結果をどのように解釈しているのかを少し詳しくみていきましょう。そのためにLinuxコマンドと終了ステータスについての理解が必要なため、一旦if文から離れて、コマンドと終了ステータスについて、お話しします。

コマンドと終了ステータス

lsやgrepなどのコマンドは全て終了時に終了ステータスと呼ばれる整数値を返します。この値は$?というシェル変数で参照できます。lsコマンドの終了ステータスをみてみましょう。
スクリーンショット 2020-06-01 19.40.53.png
$?は直前のコマンドの終了ステータス格納します。コマンドにより若干の違いはありますが、基本的にコマンドが正常に終了した場合は0を、エラー時には0以外の値を返します。次のようなシェルスクリプトを作って、コマンドの終了ステータスを確認してみましょう。

showstatus.sh
#!/bin/bash
<img width="634" alt="スクリーンショット 2020-06-01 20.14.05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630802/1047faab-784a-4725-284e-a9f668ae4f7d.png">

ls /
echo "exit status = $?"

ls /dammy                     #dammyは存在しないファイル・ディレクトリ
echo "exit status = $?"

スクリーンショット 2020-06-01 19.51.38.png
lsコマンドのマニュアルを見ると終了ステータスが2の場合は、存在しないディレクトリをしていますというメッセージです。
スクリーンショット 2020-06-01 19.54.18.png
このように、コマンドの終了ステータスを$?を用いることで確認できます。

if文と終了ステータス

if文と[コマンドのお話しに戻りましょう。[コマンドは引数に書かれた条件式を判定し、条件が正しければ0を、そうでなければ0以外の終了ステータスを返すコマンドですif文では、真偽の判定を行うとき、まず後ろに指定されているコマンドを実行します。そして、その終了ステータスが0であった場合は真、そうでない場合は偽と判定します。

if文はこのような仕組みを持つため、[以外にも任意のコマンドを持つことができます。例えばgrepコマンドは、パターンにマッチした場合に終了ステータスとして0を返すので、これを利用します。例として、/etc/passwdファイルにbashという文字列がマッチすれば、"bash found!!!"を表示するシェルスクリプトを作ってみましょう。

ifの条件にgrepコマンド
#!/bin/bash

if grep -q "bash" /etc/passwd; then  #grepでマッチした結果を表示させないための-qオプションを指定
    echo "bash found!!!"
fi

スクリーンショット 2020-06-01 20.14.05.png

testコマンドと演算子

[testコマンドは同様の機能を持ちます。次の2つの文は同じ意味を持ちます。

testコマンド(同じ意味)
if [ "$1" = "bin" ]; then
if test "$1" = "bin"; then

[ ]の方が、読みやすいので、基本的には[ ]が用いられます。また、一般的には[testも合わせて、「テストコマンド」と言います。

文字列の比較

ここからは、テストコマンドと一緒に利用するたくさんの評価演算子をみていきます。まずは比較の演算子からです。
ここでstr1, str2は任意の文字列を示しています。

演算子 内容
str1 = str2 str1とstr2が等しい
str1 != str2 str1とstr2が等しくない
-n str1 str1が空文字列ではない
-z str1 str1がから文字列である

ここでは-zを例に上げてみましょう。-zは引数が空文字列であれば真となるので、対象が空の時にデフォルト値を代入する条件文を作ってみましょう。

-zの使い方例
filename=$1                      #$1は位置パラメータ
if [ -z "$filename" ]; then    #シェル変数filename(<=$1)に値が格納されていなければ
    filename="default"           #filenameには"defaultという文字列を格納
fi

整数の比較

次に整数値を比較する演算子を紹介します。下の表で、int1, int2は任意の整数です。

演算子 意味
int1 -eq int2 int1とint2が等しい
int1 -ne int2 int1とint2が等しくない
int1 -lt int2 int1がint2より小さい
int1 -le int2 int1がint2以下
int1 -gt int2 int1がint2より大きい
int1 -ge int2 int1がint2以上

なお、これらの演算子は整数しか扱えません。では、例をみていきましょう。

2つの引数から、大きい方をシェル変数maxに代入する(if_int.sh)
#!/bin/bash

num1=$1
num2=$2
max=$num1                           #maxにnum1を代入しておく

if [ "$num1" -lt "$num2" ]; then    #条件: num1がnum2よりも小さければ
    max=$num2                       #maxにnum2を代入する
fi

echo $max

スクリーンショット 2020-06-02 11.28.47.png
なお、少数を引数に指定した場合には次のようにエラーを返されます。
スクリーンショット 2020-06-02 11.30.19.png

ファイル属性の評価

次にファイル属性を評価する演算子を紹介します。これは、多くの演算子が存在するため、使用頻度の高いものを紹介します。詳細を知りたい方はbashマニュアルの条件式(CONDITIONAL EXPRESSIONS)を参考にしてください。
スクリーンショット 2020-06-02 11.34.52.png

演算子 意味
-e file fileが存在する
-d file fileが存在し、ディレクトリである
-h file fileが存在し、シンボリックリンクである
-L file fileが存在し、シンボリックリンクdearu(-h)と同じ
-f file fileが存在し、通常のファイルである
-r file fileが存在し、読み取りパーミッションが与えられている
-w file fileが存在し、書き込みパーミッションが与えられている
-x file fileが存在し、実行パーミッションが与えられている
file1 -nt file2 file1の変更時刻がfile2より新しい
file1 -ot file2 file1の変更時刻がfile2より古い

では使用例をみていきましょう。

ディレクトリの存在確認(logdir.sh)
#!/bin/bash

logdir=/home/nossy/work/logs

if [ -d "$logdir" ]; then
    echo "ログディレクトリは: $logdir"
else
    echo "[ERROR]ログディレクトリは見つかりません"
fi

/logsディレクトリはないので、エラーを表示してくれました。
スクリーンショット 2020-06-02 11.50.44.png
/logsディレクトリを作成してから実行すると、パスを教えてくれましたね。
スクリーンショット 2020-06-02 11.51.16.png

演算子の結合

次は演算子の結合です。複数の条件式を指定したい場合には、演算子を結合することができます。

演算子 意味
条件式1 -a 条件式2 条件式1と条件式2の両方が真の場合に真(AND)
条件式1 -o 条件式2 条件式1と条件式2の少なくとも1つが真の場合に真(OR)
!条件式 条件式の真偽を逆にする(NOT)
() 条件式をグループ化する

では具体例をみていきましょう。

対象がディレクトリでかつ読み取りパーミッションがある場合という条件式
if [ -d "$sample" -a -r "$sample" ]; then
ディレクトリがないことの確認
if [ ! -d "$sample" ]; then
    echo "$sample directory does not exist"
fi

( )で囲むと条件式をグループ化できます。-o-aより優先度が低いので、`-a, -o, !"を組み合わせて使うときの優先度を決める時に使用します。

ディレクトリであり、かつ、/homeまたは/etcというパス名であるという条件式
if [ -d "$sample" -a \( "$sample" = "/home" -o "$sample" = "/etc" \) ]; then #()はメタ文字のため\でエスケープしています。

&&と||

コマンドの終了ステータスに関連したbashの構文として、複数のコマンドを連結して順に評価する方法があります。それが、&&と||です。

記法 意味
コマンド1 && コマンド2 コマンド1の終了ステータスが0である場合に、コマンド2を実行する
コマンド1||コマンド2 コマンド1の終了ステータスが0意外である場合に、コマンド2を実行する
ファイルが存在すれば、catコマンドを実行する
$ [ -f file.txt ] && cat file.txt
ファイルが存在しなければ、touchコマンドで空ファイルを作成する
$ [ -f file.txt ] || touch file.txt

if文での&&や||の利用

if文で&&を使用すると、複数コマンドの終了ステータス全てが0というAND条件を記述することができます。例をみていきましょう。

if文での&&の利用(if_and.sh)
#!/bin/bash

int1=$1
if [ "$int1" -gt 3 ] && ["$int1" -lt 6 ]; then #$int1が3より大きく、かつ、6より小さい時にif文は真
    echo "int1 > 3 and int1 < 6"
fi

スクリーンショット 2020-06-02 13.07.14.pngスクリーンショット 2020-06-02 13.23.25.png

同様に||を用いることで、いずれかのコマンドの終了ステータスが0というOR文を記述することができます。

if文での||の利用(if_or.sh)
#!/bin/bash

str=$1
if [ "$str" = "home" ] || [ "$str" = "usr" ]; then #strがhomeかusrに一致すれば真
    echo "str = home or usr"
fi

シェルスクリプトの終了ステータス

通常コマンドと同様に、作成したシェルスクリプトも終了ステータスを返すことができます。特に明示しなければ、シェルスクリプトの中で最後に実行したコマンドの終了ステータスがシェルスクリプトの終了ステータスになります。

明示的に終了ステータスを指定したい場合はexitコマンドを使用します。

明示的に終了ステータスを指定する
exit <終了ステータス> #exitコマンドを実行するとそこでシェルスクリプトは終了して指定の終了ステータスを返します。

では例をみていきましょう。

引数エラーの時に終了ステータスを1で終了する(error_test.sh)
#!/bin/bash

if [ -z "$1" ]; then #引数が指定されていない時
    exit 1           #終了ステータス1を返してシェルスクリプトは終了する
fi

ls "$1"

引数を指定した場合。
スクリーンショット 2020-06-02 13.23.25.png
引数を指定しない場合。
スクリーンショット 2020-06-02 13.25.27.png

for文

for文は、スペースやタブで区切られた単語のリストに対しての繰り返し処理を行う構文です。

for文の構造
for 変数名 in リスト   #リスト要素1つ1つに対して、do~doneまでの部分に記述された処理を実行する
do
    繰り返す処理
done

では早速例をみていきましょう。

for文の使い方(for.sh)
#!/bin/bash

for name in aaa bbb ccc
do
   echo $name   #aaa bbb ccc というリストの要素を順番にシェル変数$nameに代入してecho $nameで繰り返し出力しています
done

スクリーンショット 2020-06-02 13.32.01.png
リストの部分にはパス名展開も利用できます。

例えば、カレントディレクトリの.htmlファイルの1行目を表示したい時には、以下のような例を書きます。

パス名展開を利用したfor文
#!/bin/bash

for filename in *.html
do
    head -n 1 "$filename"
done

また、 リストの部分にはコマンド置換を記述することも可能です。

コマンド置換を利用したfor文
#!/bin/bash

for i in $(seq 1 5) #seqコマンドは数値列を出力するコマンド。 $ seq 1 5 => 1 2 3 4 5
do
    touch "000${i}.txt"
done

スクリーンショット 2020-06-02 13.41.01.png

コマンドライン引数とfor

for文ではリストtosite$@を指定して、全てのコマンドライン引数に対して処理を行うケースが頻繁にみられます。

コマンドライン引数$@をリストに指定(parameters.sh)
#!/bin/bash

for parameter in "$@"
do
    echo "$parameter"
done

スクリーンショット 2020-06-02 13.45.11.png
なお、for文では$@を対象とすることが多いのでin <リスト>を省略すると自動的に$@がリストの対象とみなされるようになっています。下の2行は同じ意味です。

for文の省略系
for parameter in "$@"
for parameter

ここまでの復習

引数に複数ファイルをとって、引数がディレクトリの場合はlsを実行、ファイルの場合は先頭の5行を出力するシェルスクリプトを作ってみましょう。また、それぞれの引数がfileなのかdirectoryなのかを出力してみましょう(〇〇 is a regular file.)

復習(test.sh)
#!/bin/bash

for parameter in "$@"
do
    if [ -d "$parameter" ]; then
        echo "$parameter is a directory."
        ls -l "$parameter"
    elif [ -f "$parameter" ]; then
        echo "$parameter is a regular file."
        head -n 5 "$parameter"
    fi
done

スクリーンショット 2020-06-02 14.00.37.png

case文

caseは、指定された文字列がパターンにマッチするかどうかを判断して、マッチしたパターンに対応する処理を行うための制御構造です。

case文の構造
case <文字列> in
    <パターン1>)
        処理1
        ;;
    <パターン2>)
        処理2
        ;;
     ...
esac

caseで指定された文字列は、各パターンにマッチするかどうか上から順に評価されて、マッチしたパターンのブロックに書かれた処理を実行します。どのパターンにもマッチしない場合には、そのままcase文を抜けます。早速例をみていきましょう。

ファイル名によって処理を分岐(case.sh)
#!/bin/bash

case "$1" in
    *.txt)            #ワイルドカードが使用できる
        less "$1"
        ;;
    *.sh)             #ワイルドカードが使用できる
        vim "$1"
        ;;
    *)                # *)は上記のどの条件にも一致しなかった場合の処理として使用される
        echo "not supported file : $1"
        ;;
esac

また|を使って複数のパターンを記述することも可能です。

|を使った複数パターンの記述
#!/bin/bash

case "$1" in
    start|stop)     #startまたはstopにマッチした場合はOK
        echo "OK"
        ;;
    *)
        echo "NG"
        ;;
esac

while文

while文は指定した条件が真である限り繰り返し処理を行う制御構文です。

while文の構造
while <コマンド>
do
    繰り返し処理
done

早速例をみていきましょう。次の例は、シェル変数iが10以下の数値である場合に\$iの値を表示してから、2を加えるという動作を繰り返します。$iが10よりも大きくなったら処理を終了します。

testコマンドによるwhile文のループ
#!bin/bash

i=1
while [ "$i" -le 10 ]
do
    echo "$i"
    i=$((i + 2)) #bashの算術式展開の表記 whileと一緒に用いられることが多い。下記で解説
done

算術式展開

shで書かれたシェルスクリプトは、簡単な足し算をするときも次のようにexprという外部コマンドを使っています。これはループの中で使用する場合など、回数をこなさないといけない場合に、処理速度が非常に遅くなります。

exprコマンド
i=`expr $i + 2`

一方、$(( ))はbashの算術式展開と呼ばれる機能を使用しています。$(( ))と括ることにより、中の文字列を計算式として扱うことができます。またbashの算術式展開は読みやすく、動作も早いという利点を持っています。そのため、bashスクリプトでは積極的に利用しましょう。

算術式展開
i=$((i + 2))

シェル関数

シェルスクリプトを書いていると、同じ処理を何度も実行する場面がよくみられます。このような時は処理をひとまとめにして、関数にしておくと便利です。
シェルスクリプトで利用される関数は、シェル関数と呼びます。これは次のようにfunctionを用いて定義します。

シェル関数の定義
基本形
function <関数名> ()
{
    処理
}

省略形1           #()を省略した形
function <関数名>
{
    処理
}

省略形2           #functionを省略した形 最もよく使われている
<関数名> ()
{
    処理
}

では、早速例をみていきましょう。次の例ではhomesizeという関数を定義して、シェルスクリプトの最後で呼び出しています。

シェル関数の定義と使用例(function.sh)
#!/bin/bash

homesize ()    #関数を定義します
{
    date
    du -h ~ | tail -n 1
}

homesize       #シェルスクリプトを実行すると、まずhomesize関数が呼び出されます。その中身として、duやtailコマンドが実行されます。

なお、シェル関数を使用する際には、必ず利用する箇所よりも前に定義しておく必要があります。関数定義のうしろで関数を呼び出すとエラーになります。

シェル関数内での位置パラメータ

シェル関数ないでも位置パラメータ$1,$2...は利用できます。ただし、シェル関数の中ではこれらはコマンドライン引数ではなく、関数への引数が参照されます。次のようなシェルスクリプトを作成して確認してみましょう。

シェル関数での位置パラメータ(func_parameters.sh)
#!bin/bash

print_parameters ()
{
    echo "\$1 = $1"
    echo "\$2 = $2"
    echo "\$3 = $3"
    echo "\$4 = $4"
    echo 
    echo "$# arguments"
    echo "script name = $0"
}

print_parameters aaa bbb ccc  #シェル関数に引数を渡している

スクリーンショット 2020-06-02 15.07.55.png
上の例では、コマンドライン引数には何も与えていませんが、シェル関数への引数が、位置パラメータとして参照されているのがわかります。
なお、$0だけは、元のシェルスクリプトのままになっているので、$1,$2...とは扱いが異なるため、特殊パラメータと言われています。

シェル関数のステータス

通常のコマンドと同様にシェル関数も終了ステータスを返します。通常はシェル関数内で最後に実行されたコマンドの終了ステータスが、そのままシェル関数の終了ステータスとなります

明示的に終了ステータスを返したい場合は、returnコマンドを使用します。

明示的にシェル関数の終了ステータスを返す
return <終了ステータス> #returnコマンドを実行するとそこでシェル関数の動作は終了して呼び出し元に返ります。
引数が指定されていない場合は終了ステータスとして1を返す関数
checkparam ()
{
    if [ -z "$1" ]; then
        return 1
    fi

    ls "$1"
}

関数を実行後に$?を出力すると、エラーが起きたかどうかを確認することができます。

参考資料

新しいLinuxの教科書

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

お気に入りのtmuxの複数ペインとvimのセッションの復元・自動化

MacやLinuxのターミナルマルチプレクサtmuxで開発作業は、複数のペインやウインドウを開いて作業しますが、毎回同じな作業が発生するため、自動化します。

プロジェクトのパスに移動し、tmuxの上部ペインにvim起動と同時にセッションを復元し、tmuxの下部ペインに
カレンダーを表示するバッチファイルです。

自動化のバッチファイルの内容

$ cat project.sh
#!/bin/bash

# 作業ディレクトリフルパス名
WORK_DIR="$HOME/project/"
# セッション名
SESSION="project01"
# ウインドウ名
WINDOW="main_window"
tmux new-session -d  -s $SESSION -n $WINDOW -c $WORK_DIR
#tmux split-window -h -c "$DIR"
tmux split-window -v -c "$DIR"
# 下部ペインのサイズ変更
tmux resize-pane -D 5
# ペイン0に移動
tmux select-pane -t 0
# vimセッションの再開
tmux send-keys -t 0.0  'vim -S Session.vim' C-m
# calコマンドの実行
tmux send-keys -t 0.1  'cal' C-m
# セッション名を指定してアタッチ
tmux attach -t $SESSION

バッチの実行方法

$ bash project.sh

ターミナルマルチプレクサtmuxの表示結果

tmux_vim_cal_20200602_135846.png

tmuxのバージョンの確認

$ tmux -V
tmux 3.1b
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ツール・環境厨がメインPCをLinuxからWindows+WSL2に乗換えた理由と作業メモ

はじめに

偉そうなことばかり言ってますが他人の作ったソフトを使うことしかできない素人です。そして宗教色も強いです。詳しい方もっとスマートなやり方・ご意見等あれば教えて下さい。

筆者の環境

  • Thinkpad X1 Carbon 2018
  • 家ではUSB Type-C ドッキングステーションに接続し、見た目はデスクトップ
    • 4K, FHD, FHDのトリプルディスプレイ
  • US Keyboard
  • 日常用途も開発用途も両方

乗り換えを決意した経緯

アドバンスドユーザにはLinuxこそ至高だと思っていた。全て自分で設定・選択できる自由。アドバンスドユーザ用の豊富な無料のツール。そして最高のラップトップ(=Thinkpad)にも自由に入れられる。

しかし、Linuxには大きな問題がある。基本的にGUI周りが弱い。数ある商用サービスはたいていLinuxをきちんとサポートしていない。(逆にサポートしているDropbox, Spotify等は素晴らしい)
それでもLinuxの便利さは、これらの欠点を補って余りあると思っていた。

しかし、ある日久しぶりにWindowsを立ち上げたら(当然デュアルブート環境なのだ)ブラウザのレンダリングが爆速ではないか。ウィンドウを電光石火で切り替えて移動しても描画がしっかり追いついてくる。私は家ではノートPCのオンボードのグラフィックで計6K外部出力しているので、gnomeを使っているときに動作がカクついてもそれはある程度仕方ないと思っていた。しかし、Windowsでは快適にそれらが動作するのだ。LinuxでもHardware accelerationが動作するようにドライバーの設定はしたはずだが、やはり対応していないアプリも多いし(zoom, chromeのvideo decode等)、なぜかカクカクなのである。きっと計算プログラムを走らせるだけならLinuxにCLIでログインしてコマンドを叩けばLinuxのほうが速いのだが、日常用途も考えるとWindowsのほうがサクサクなのだ。そして、Windowsは最近WSL2でLinuxカーネルが動くようになり、wingetみたいなスマートな取組みも始まっている。正直ここが一番大きな乗り換えた理由である。

そして第二には、やはりほぼ全てのソフトがWindows向けに最適化されたアプリ・ドライバを提供しているのも大きい。Windowsに乗り換えれば公式Google Driveクライアントもあるし、ゴミLINEもネイティブアプリを提供している。4kHDRの動画をYoutubeでみてもHardware支援が効くし、Amazon Prime VideoもFull HDで見れる。

そして第三には、今は学生だが就職したらLinuxを使えるような職場かは現時点ではわからない。Windowsでも効率的な作業ができるようになっておけば、就職してから活躍すること間違いなしである。()

gnomeをやめてi3とかにすれば、カクカクする問題は解決するかもとかは考えたが、また時間をかけて環境を整えても、結局いろんなアプリが非対応という事実は変わらないので、ならWindowsを快適にしたほうがイイ気がしてきてこうなった。

Why not MBP?

大抵の人はmacでいいじゃんと言うだろう。もちろんmacにもいいところはあるのだがハードがやはりおもちゃであるのだ。MacOSがThinkpadに乗ればいいのだが、、、以下数ある理由を抜粋。

  • パソコンなのになぜかキーボードの形をしたまな板が本体の約半分を占めている。
  • 見栄えしか考えてないグレアディスプレイ(デザイナーとかはいいのだろうが、この記事はあくまでもdeveloper視点である。)
  • 物理的に重い。ベゼルも細くはない。
  • Ligitning()じゃなくてType-Cなのは当然だとしても、逆になんでType-Cしかないの?確かにそれ将来的には理想形だけど現実的にはアダプタ持ち歩くだけにしかならないよね
  • なぜかProのほうで物理キーを廃止してTouch Bar()
  • トラックパッドはいいらしいが、男は黙ってキーボードなのでどうせ使わない関係ない。
  • スペックに対してやはり高い、高すぎる。(筆者はコンピュータに関しては金にあまり糸目をつけないので直接の理由ではないが、こんなに高いのにもっと安いThinkpadにボロ負けしていると考えるとやるせない)
  • デザイン重視など実用的な工業製品としての質が低い
    • すぐ故障する
    • 排熱性能()
    • 低クロック推移()
  • mac OSは確かにWindowsより使いやすいだろう。しかしやはり欠点はある
    • Appleサービスと親和性は高いけど、Appleサービス(iCloudとか)はゴミが多いのでどうせGoogleサービスしか使わない。というかGoogleが強すぎる。Appleサービスと親和性が高かろうが関係ない。
    • Dockerがネイティブで使えない
    • Unixではあるが、細かなところがLinuxと違ってうざい

以上を考えるとWindows on Thinkpadが最高なのではないかという結論に至った。(但し開発用途にしか使わないとかシングルディスプレイでGPU支援がいらないとか環境によってはLinux on Thinkpadであろう)


さて御託を並べるのはここらへんにしてここからはWindowsに乗換えるにあたって調査したこと・メモを記す。

Windowsの環境構築

方針

  • 開発は全てWSL2上、間違ってもwindowsのゴミのようなpath環境や改行コードとは関わらなくていいようにする。
  • 但し、VSCodeとJetbrainsIDEの問題はある。少なくともWSL1ではVSCodeはWSLにアタッチするのに1秒弱はかかるし、Jetbrainsについては未調査。Linuxのときは$ code .を叩けば一瞬で開いた。
  • ブラウザとかのその他日常用途アプリは全部windowsに任せよう。きっとwingetにすぐほとんどは対応するだろう。GPU支援アプリ万歳

以下乗り換えにあたって調べたツール達

WSL2

  • ディストリビューションはやっぱり安定したローリングリリースなManjaroがいいんだけどうまくインストールできるのだろうか?
    • 一応有志が取り組んでいたけど不安定そうなので、素直にUbuntuを導入して、パッケージ管理はlinuxbrewにした。 Path管理とかめんどくさかったし、普通にaptに戻した。
  • shellはいままでzsh+zgen+preztoでサクサクだったけど、これを機にfishに乗り換え。
  • 現時点ではfish+fisherでやってる。shell scriptの文法がbash/zshと大きく異なる以外は満足
  • dockerはUbuntu上でそのままaptで持ってくるか、windowsのdocker for desktop使うか迷い中。aptのほうがwindows側の環境汚さずに済みそうだけど、windowsのほうが後々便利だったりするのかな?

ターミナル

guakeみたいなdropdown terminalがよい。

現時点での候補

  • Hyper: 分割もあるしプラグインもよい。しかし少し遅い。
  • Fluent Terminal: 若干遅い。Dropdownオプションがなさそう。Storeにあるのはよい
  • alacritty: 確かに速い。但しdrop downのオプションはない。Windows Managerがサポートするべき機能だとissueで言われてる。(だったらWindowsでそれを実現するツールを教えてくれ)
  • Windows Terminal: 発展途上だが公式なので安定感はある。
  • cmder: Dropdownあり、重いのでなしか
  • ConEmu: cmderのフォーク元らしい。きっとこれも重い
  • Terminus: issueによればdropdownに対応しているらしい

guakeが使えなくなるので、いい機会だしtmuxも導入することにする。

参考リンク

とりあえずHyperにしてみようかな。
Windows TerminalはGPUサポートしてるからこれにDrop down optionが実装されたら乗換えるかも。
Hyperとりあえず動いた。overlayのパッケージがうまく動かなかったが㏚のコードを参考にして修正したらうまくいった。

Terminusにした。マルチプラットフォームだがWindowsをメインターゲットにしててバグが少ない。Hyperではtabのvertical splitさえバグでできなったので乗り換えた。欠点としてパフォーマンスが悪い。今まで重いと言われてるzsh使ってるのにシェルが重いとか思ったことなかったけど、初めてシェルが重いとかいう概念がわかった。

っていうか今更だけどdropdownがないターミナルでもホットキーでshow/hideできるツールいれれば疑似的に再現できるのでは?もう疲れたからとりあえずTerminusのままいくけど。

さらに追記、Terminus重すぎてストレスマックスだったのWindows Terminalに乗り換えた。むちゃくちゃ速い。やっぱ公式は安定感が違う。速いと言われてるalacrittyより速い気がする。多少機能が少なくても、一番使うところなので基礎がしっかりしてるものを選ぶといいね。こんな便利なものをMicrosoftが公式に出してると考えると感動する。

Package manager

どうせchocolateyとかも不完全だし期待を込めてwingetにする。これで全てが済む世界になってほしい。pamacが恋しい

Tiling Window Manager

ここはちゃんとしたものがあるか心配。有料でもいいので安定してキーボードで操作できるものがほしい。
- bug.n: だめだったうまく動かない。
- HashTWM: だめだったうまく動かない。
- MaxTo: 試用版はあるが用途が異なる気がする。
- AquaSnap Pro: 試用版試した。バグ等なくきちんと動作するが、これはTile WMではない。単にWindows分割とかの便利ツール
- Stack Window Manager: これもAquaSnapと同じ系統
- divvy: 用途が異なる。

どうやらbug.nはうまく動かなかったが、きちんとconfigすればうまくいくかも。モニタごとにscalingが違うからちょっと無理そうだけど。
色々試した結果どうにかしてbug.nを動かすしかないかも。
それなりに動くようになったけど、遅い。ネイティブでWindow Managerを入れ替えられるわけではないのでしょうがないか。こんなUXならもう標準のものでよい。

ファイルエクスプローラ

WSL2上のrangerでプレビューとか含めてうまく見れるんだろうか。不安。

エディタ

VSCodeしかないよね

IDE

  • Jetbrains系がVSCodeみたいに手軽にWSL2とアタッチできるのか調査が必要
  • X Serverを立ち上げてGUIもLinux側で立ち上げればいいかもしれないけど、勝手なイメージでなんかカクつきそう。せっかくwindowsなのでGUIはWindowsから使いたい。
  • こちらの末尾で言及されているところを見ると大丈夫そう。

Windowsのためのツール

システム変更系

  • fastwindowswitcher: windowsのalt-tabむちゃくちゃ見にくいので導入。Gnomeではalt-tab中にフォーカスウィンドウに色がつけれてすごい見やすかった。 うまく動作しないマルチディスプレイ対応とは書いてあるけどおそらくバグがある。
  • win-10-virtual-desktop-enhancer: デフォルトでwindowsを隣のvirtual desktopに持っていくshortcutないのやばくない?これもオリジナルは開発が止まっており、一番活発そうなフォーク版を試したがダメだった。代わりにMoveToDesktopは動いた。
  • StrokersPlus: ゆうてご飯食べてるときとかは片手でマウス使うので、そのときのマウスジェスチャ用
  • tascher: windowをインクリメンタルサーチで切り替えられる。Alt-Tabを連打しなくてもよくなったが、手順に従ってインストールしてもmigemoに対応させることができないがとりあえず放置。

クリップボードマネージャ

Win + Vはいいんだけど、あれキーボードで操作完結しないの?俺の使い方が間違ってる?要調査。(テキスト入力中に限りキーボードで選択できました。これならとりあえずは看過できる)

プロセス管理

Windows側のプロセスが暴走したときってどうすればいいの?WSL2のhtopとかgtopじゃwindowsプロセスは扱えないよね?
訳わからないPowershell立ち上げてコマンド叩くのも嫌だけど、タスクマネージャを立ち上げてマウスポチポチとかはもっと勘弁。

ファイルエクスプローラ

最低限tab化ができるもの。Clover3(トロイの木馬だった笑、Windows Defender万歳)かQTTabbar。

QTTabbar使ってみたが想像よりよい。標準のエクスプローラに拡張で入れる形なので動作が不安定になったら嫌だなとか思っていたが、細く設定できるし、動作も安定してるしこのレベルのものを個人で作れるとは、、、そりゃ海外サイトでも紹介されるわけだ。(日本の方が開発されているが英語にも対応している。)
ただかなり重いので、使わない機能はできる限りオフにすること。

便利ツール

  • Powertoys: 恥ずかしいことにこのMicrosoft公式の便利ツールの存在を最近知った。これいれよう。プレビュー版なので公式なのに、ctrlキーのswapがうまく行かなかった。代わりにkeyswap.exeを使った。
  • Mini Tool Partition Wizard: LinuxのほうにPartitionを侵食させるときに使えるだろう。

exif関連

これはただの自分用忘備録である。
- GPSBabel: これでtimeline jsonをgpxに変換
- Geotag: これを使って写真にタグ付けする。

デバイスドライバ

  • Driver Booster: 以前使っていて機能には不満ないんだけど、勝手に他のソフトいれるし、スタートアップ自動起動も意地でもしたいみたいだし、ちょっとマルウェアちっく。代替を探しておく。

ウェブサービスのクライアントアプリ達

Station・bitwarden・mendeleyとかいれといた。

感想

  • Windowsは情報が一番多いと思ってたけど、英語で探しててもLinux文化圏の人間がほしいような情報が少ない。やはりまともな人間は誰も使ってないのか?ちょっとmacOSが羨ましくなった。
  • Windowsは日常用途アプリはしっかりサポートされててこの点はとてもよい。Chromeがサクサクになったのはほんとに快適。しかしターミナルとかはあまりのまともなものの少なさには参ってしまった。
  • アドバンスドユーザなら当然変更したいような(エクスプローラのタブ化や仮想デスクトップの拡張など)の機能であっても、それなりにツールはあるが個人でやっていてメンテナンスされていなかったり、商用で有料だったりで、選択肢はとても少ない。世の中の星の数ほどいるWindowsユーザはこれでいいのか?
  • GUIであっても開発系のアプリに関してはLinuxのほうが安定してるし、種類も豊富だし、当然どこのパーツも入れ替えが効くのですごい快適だったと気づいた。またしばらくしたらLinuxに戻るかも。
  • 2020のmacbookは一応キーボードを積むようになったらしいので、一回限りと思って試しに買ってみるかも。ゆうてMac OSは全然触ったことないので、ちゃんと触ってもっとOS自体の使い勝手も知りたい。

ToDo

  • rangerのpreviwe設定
  • Terminusのhide後にたまにwindowにfocusが戻らない事象を改善
  • tascherのmigemoを動くようにする。
  • Jetbrains系のアタッチテスト
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

tsharkコマンドでpcapデータを解析

1.tsharkコマンドとは
2.環境設定
3.実行
4.pcapファイルのフィルタリング方法
5.オプション
6.参考

tsharkコマンドとは

Wiresharkの実行をCLIで実現できるものです。
CLIなので、並列処理、シェルスクリプトでの記載、cron、grepなどなど、CLI職人にとってはpcapデータをかなり楽に扱えるようになります!

環境設定

本記事ではMacOSで試しています。
まずお持ちのMacでtsharkを利用できる状態にします。GUIでもCLIでもどちらからでも可能です。

GUI(Webから)でインストールの場合
 下記からインストールできます。
 https://www.wireshark.org/download.html

CLI(ターミナル)でインストールの場合

インストール
 brew install wireshark

※まだhomebrew(brewコマンド)が利用できない場合は、下記を参考に利用できるようにしてみてください!
Homebrewのインストール方法

実行

早速実行していきましょう!今回はtest.pcapというデータを見ていきます。

実行
 tshark -r test.pcap

これでデータの中身が確認できたと思います。
ちなみにデータの並び方と表示されている項目はデフォルト状態ですが、確認したいデータや表示順などを指定することができます。
GUIのWiresharkで列の表示変更を行った場合もtsharkコマンドの結果に影響されます。

pcapファイルのフィルタリング方法

今回は下記の条件をつけてフィルタリングして、再度実行してみましょう。
条件
(※)通常のWireShark(GUI)で利用できるフィルター
 ・smb2プロトコルの通信に絞る
   smb2.tree && tcp.dstport==445
 ・ファイル名や利用アカウント名が抜けている余分な通信は除去する
   smb2.filename != "" && smb2.acct != ""
表示
(※)通常のWireShark(GUI)で利用できる列の書き方
 ・アカウント名
   smb2.acct
 ・フォルダパス(共有パス)
   smb2.tree
 ・操作ファイル名
   smb2.filename
 ・アクセスしている端末名
   smb2.host

実行
 tshark -r test.pcap -T fields -e smb2.acct -e smb2.tree -e smb2.filename -e smb2.host -Y 'smb2.tree && tcp.dstport==445 && smb2.filename != "" && smb2.acct != ""'

下記のようにパイプやリダイレクトを利用して簡単に扱えるデータに変換ももちろん可能です。

参考
 tshark -r test.pcap <オプション系> | grep -i test
 tshark -r test.pcap <オプション系> > test.csv

オプション

オプション 内容
-i <interface> キャプチャするインターフェイスを指定
-f <capture filter> libpcapフィルタsyntaxによるフィルタを指定
-s <snaplen> snapshot lengthを指定(デフォルト:65535)
-p プロミスキャスモードを使用しない
-y <link type> リンクレイヤータイプを指定(デフォルト:first appropriate)
-D インターフェイスリストを表示
-L インターフェイスのリンクレイヤータイプリストを表示
-c <packet count> 指定したパケット数で停止(デフォルト:無限)
-a <autostop cond.> ・duration:NUM
NUMで指定した秒数経過により停止
・filesize:NUM
NUMで指定したサイズ(KB)に保存ファイルが達したら停止
・files:NUM
NUMで指定した数の保存ファイル数に達したら停止
-b <ringbuffer opt.> ・duration:NUM
NUMで指定した秒数経過により次のファイルへ保存
・filesize:NUM
NUMで指定したサイズ(KB)に保存ファイルが達したら次のファイルへ保存
・files:NUM
NUMで指定した数の保存ファイル数に達したらファイルの置き換え
-r <infile> パケットfileから読出し
R <read filter> Wiresharkディスプレイフィルタを指定
-n すべての名前解決を無効にする(デフォルト:有効)
-N <name resolve flags> 特定の名前解決を有効にする
-d <layer_type>==<selector>,<decode_as_protocol> 特定のポートを特定のプロトコルと紐付け
tcp.port==8888,httpの場合は
「tcpポート8888番はhttpとする」となる
-C <config profile> 設定ファイルを指定
-F <output file type> 出力ファイルタイプを指定
-V 表示にパケットツリーを追加
-S [-w]オプションを有効にしている場合でもパケットを表示
-x hex、ACSIIダンプ表示を追加
-e <field> アウトプットしたいフィールドを指定

参考

Homebrewのインストール方法
tshark オプションメモ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Bulls and Cowsをシェルプログラムで作成してみた

はじめに

Bashプログラミングの小ネタとして作成しました。
第6弾です。今回はなかなか手強かったです。

Bulls and Cowsとは

Bulls and Cowsに関してはWikipediaこちらをご確認ください。

もともとは文字列当てゲームですが、
今回は数字当てゲームとして作成してみます。

ソース

#!/bin/bash

function chkAns {
  bull=0
  cow=0
  num=$1
  dig=$2
  ans=$3

  for i in $(seq 1 $dig)
  do
    for j in $(seq 1 $dig)
    do
      if [[ ${num:i:1} == ${ans:j:1} && $i == $j ]]
      then
#       echo bull: $bull        #for debug
        (( bull = bull + 1 ))
      elif [[ ${num:i:1} == ${ans:j:1} && $i != $j ]]
      then
#       echo cow: $cow          #for debug
        (( cow = cow + 1 ))
      fi
    done
  done

  if (( bull == dig ))
  then
    echo -e "$dig bulls ! You did it !"
    exit
  else
    echo -e "$bull bull and $cow cow."
  fi
}

echo "Welcome 'Bulls and Cows' Game"
echo -e "Please input digits of numbers => \c"
read digits

tmp=$(shuf -i 0-9 -n $digits -z)
answer=${tmp:0:3}

#echo $answer  #for debug

for k in $(seq 1 10)
do
  echo -e "Input $digits numbers of your answer. (${k} time) => \c"
  read num

  chkAns $num $digits $answer
  if (( $k == 10 ))
  then
    echo "You failed 10 times..."
  fi
done

echo -e "The answer is '$answer'"

$RANDOMでも良かったですが、信用してないので採用しませんでした。
代わりに、shufコマンドを使いました。

実行結果(正解する)

$ ./bulls_and_cows.sh
Welcome 'Bulls and Cows' Game
Please input digits of numbers => 3
./bulls_and_cows.sh: 行 39: 警告: command substitution: ignored null byte in input
Input 3 numbers of your answer. (1 time) => 321
2 bull and 0 cow.
Input 3 numbers of your answer. (2 time) => 324
2 bull and 0 cow.
Input 3 numbers of your answer. (3 time) => 325
3 bulls ! You did it !

「警告: command substitution: ignored null byte in input」のメッセージは、ヌルバイトが含まれていると出るようです。
ただ、Nullを使わないとN桁の生成が難しかったので無視しています。
良い対処方法があればコメントください。

実行結果(失敗する)

真面目に正解しようとしています。

$ ./bulls_and_cows.sh
Welcome 'Bulls and Cows' Game
Please input digits of numbers => 3
./bulls_and_cows.sh: 行 39: 警告: command substitution: ignored null byte in input
Input 3 numbers of your answer. (1 time) => 345
1 bull and 0 cow.
Input 3 numbers of your answer. (2 time) => 219
1 bull and 0 cow.
Input 3 numbers of your answer. (3 time) => 398
1 bull and 0 cow.
Input 3 numbers of your answer. (4 time) => 470
1 bull and 1 cow.
Input 3 numbers of your answer. (5 time) => 709
1 bull and 0 cow.
Input 3 numbers of your answer. (6 time) => 507
2 bull and 0 cow.
Input 3 numbers of your answer. (7 time) => 504
1 bull and 0 cow.
Input 3 numbers of your answer. (8 time) => 570
1 bull and 1 cow.
Input 3 numbers of your answer. (9 time) => 407
2 bull and 0 cow.
Input 3 numbers of your answer. (10 time) => 307
2 bull and 0 cow.
You failed 10 times...
The answer is '567'

おわりに

このプログラムを作成することで

  • 変数
  • 変数の操作
  • 条件式
  • 繰り返し構文
  • 関数
  • readコマンド
  • shuf(シャッフル)コマンド

が理解できました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Remote Processor Framework (2/3)

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/Documentation/remoteproc.txt

Remote Processor Framework

API for implementors

  struct rproc *rproc_alloc(struct device *dev, const char *name,
                const struct rproc_ops *ops,
                const char *firmware, int len)

Allocate a new remote processor handle, but don't register it yet. Required parameters are the underlying device, the name of this remote processor, platform-specific ops handlers, the name of the firmware to boot this rproc with, and the length of private data needed by the allocating rproc driver (in bytes).

新しいremote processor handleを確保しますが、まだ登録は行いません。要求されるパラメータは、基礎となるデバイス、このremote processorの名称、プラットフォーク特有のops handlers, このrpocを起動するためのファームウェアの名称、そして、rpoc driverが必要とするprivate dataの長さ(byte単位) です。

This function should be used by rproc implementations during initialization of the remote processor.

この関数は、remote processorの初期化している間の、rpoc 実装によって利用されるでしょう。

After creating an rproc handle using this function, and when ready, implementations should then call rproc_add() to complete the registration of the remote processor.

この関数を用いてrproc handlerを生成した後、準備ができたら、実装ではremote processorの登録を完了するために、rpoc_add()を呼び出します。

On success, the new rproc is returned, and on failure, NULL.

成功したら、新しいrpocが戻り値になります、失敗したNULLです。

note::

never directly deallocate @rproc, even if it was not registered yet. Instead, when you need to unroll rproc_alloc(), use rproc_free().

「絶対に」 rpocで直接deallocateしないでください。仮にそれが登録されていなかったとしても、その代わりに、rproc_alloc()を基に戻すためには、rproc_free()を使ってください。

  void rproc_free(struct rproc *rproc)

Free an rproc handle that was allocated by rproc_alloc.

rproc_alloc()で確保したrpoc handleを開放します。

This function essentially unrolls rproc_alloc(), by decrementing the rproc's refcount. It doesn't directly free rproc; that would happen only if there are no other references to rproc and its refcount now dropped to zero.

この関数は、rprocのrefcountを減らし、rproc_alloc()を基に戻します。これは直接cprocを開放しません。もし、他からrpocが参照されておらず、refcountが0にまで落ち込んだ時だけ、解放します。

  int rproc_add(struct rproc *rproc)

Register @rproc with the remoteproc framework, after it has been allocated with rproc_alloc().

rproc_alloc()で確保した後、rpocをremoteproc frameworkに登録します。

This is called by the platform-specific rproc implementation, whenever a new remote processor device is probed.

これは、新しいremote processor deviceがprobeされるたびに、platform特有のrpoc実装によって呼び出されます。

Returns 0 on success and an appropriate error code otherwise.

成功時には0が、それ以外の場合にはおそらくエラーが戻り値になります。

Note: this function initiates an asynchronous firmware loading context, which will look for virtio devices supported by the rproc's firmware.

注意:この関数は非同期にfirmware load contextを開始し、rprocのfirmwareがサポートするvirtio deviceを探します。

If found, those virtio devices will be created and added, so as a result of registering this remote processor, additional virtio drivers might get probed.

もし見つかった場合、それらのvirtio deviceは生成され追加されます。そのため、このremote processorを登録した結果、追加のvirtio driverが追加されることがあります。

  int rproc_del(struct rproc *rproc)

Unroll rproc_add().

rproc_add() を基に戻します。

This function should be called when the platform specific rproc implementation decides to remove the rproc device. it should only be called if a previous invocation of rproc_add() has completed successfully.

この関数は、platform特有のrpoc実装をproc deviceから削除する時に呼び出します。それは、rpoc_add()が完全に成功した場合にだけ、呼び出す必要ががあります。

After rproc_del() returns, @rproc is still valid, and its last refcount should be decremented by calling rproc_free().

rproc_del()から処理が戻った後、rprocはまだ有効であり、その最後のrefcountはrpoc_free()を呼び出す事で減少します。

Returns 0 on success and -EINVAL if @rproc isn't valid.

成功した場合には0が、有効なrprocではない場合には-EINVALが帰ります。

  void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type)

Report a crash in a remoteproc

remoteprocのcrashを報告します。

This function must be called every time a crash is detected by the platform specific rproc implementation. This should not be called from a non-remoteproc driver. This function can be called from atomic/interrupt context.

この関数は、platform特有のrpoc実装によって、crashが検知されたら毎回呼ばれるべき関数です。これは、remote-proc driver以外から呼ばれるべきではありません。この関数は、atomic/interrupt contextから呼び出すことができます。

Implementation callbacks

These callbacks should be provided by platform-specific remoteproc drivers::

これらのコールバックは、platform特有のremoteproc driverによって提供されます。

  /**
   * struct rproc_ops - platform-specific device handlers
   * @start:    power on the device and boot it
   * @stop: power off the device
   * @kick: kick a virtqueue (virtqueue id given as a parameter)
   */
  /**
   * struct rproc_ops - platform-specific device handlers
   * @start:    電源投入及び起動
   * @stop: 電源切断
   * @kick: virtqueueを実行(virtqueueはパラメータで与えられる)
   */

  struct rproc_ops {
    int (*start)(struct rproc *rproc);
    int (*stop)(struct rproc *rproc);
    void (*kick)(struct rproc *rproc, int vqid);
  };

Every remoteproc implementation should at least provide the ->start and ->stop handlers. If rpmsg/virtio functionality is also desired, then the ->kick handler should be provided as well.

それぞれのremoteproc実装には、->start, ->stop handlerが少なくとも提供されます。もし、rpmsg/virtio 機能がまた必要であれば、->kick handlerもまた提供されます。

The ->start() handler takes an rproc handle and should then power on the device and boot it (use rproc->priv to access platform-specific private data). The boot address, in case needed, can be found in rproc->bootaddr (remoteproc core puts there the ELF entry point). On success, 0 should be returned, and on failure, an appropriate error code.

->start() handlerは、rproc handleを用い、デバイスの電源を投入し起動します(rpoc->priveを、platform特有のprivate dataとして用います)。起動アドレスが必要な場合には、rptoc->bootaddr()にて見つけることができます(remoteproc coreはこれをELF entry pointとしてセットします)。成功した場合には0が戻り、失敗した場合には適切なエラーコードが入ります。

The ->stop() handler takes an rproc handle and powers the device down.  On success, 0 is returned, and on failure, an appropriate error code.

-> stop() handlerは、rpoc handleを伴い、デバイスの電源を切断します。成功した場合には0が戻り、失敗した場合には適切なエラーコードが入ります。

The ->kick() handler takes an rproc handle, and an index of a virtqueue where new message was placed in. Implementations should interrupt the remote processor and let it know it has pending messages. Notifying remote processors the exact virtqueue index to look in is optional: it is easy (and not too expensive) to go through the existing virtqueues and look for new buffers in the used rings.

-> kick() handlerはrpoc handleと、新しいメッセージをとして設定されるvirtqueueのindexを伴います。実装ではremote processorの輪割り込み、messageがpendingされていることを知ります。検索する正確なvirtqueueインデックスをremote processorに通知することはオプションです。既存のvirtqueueを調べて、使用済みのringで新しいbufferを探すのは簡単です(計算コストは高くありません)。


もともと、Linux Kernelのソースコードの一部なので、GPLv2扱いになる(はずの認識)。

https://www.kernel.org/doc/html/latest/index.html

Licensing documentation

The following describes the license of the Linux kernel source code (GPLv2), how to properly mark the license of individual files in the source tree, as well as links to the full license text.

https://www.kernel.org/doc/html/latest/process/license-rules.html#kernel-licensing

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

フィボナッチ数列を表示するシェルプログラム

はじめに

Bashプログラミングの小ネタとして作成しました。
第5弾です。

フィボナッチ数列を表示

フィボナッチ数列とは何か、詳しくはこちらをご確認ください。

簡単にいうと、2つ前の項と1つ前の項を足し合わせていくことでできる数列です。

ソース

#!/bin/bash

m=0
n=1

echo -n "please input number => "
read num

if (( $num <= 1 || $num >= 2))
then
  echo $m
  echo $n
fi
(( num +=2 ))

for i in $(seq 1 $num)
do
  (( o = $m + $n ))
  echo $o
  m=$n
  n=$o
done

もっときれいに書けそうですね…

実行結果

$ ./fibonacci.sh
please input number => 8
0
1
1
2
3
5
8
13
21
34
55
89

おわりに

このプログラムを作成することで

  • readコマンド
  • 条件式
  • 条件演算子
  • 変数
  • Bashのお作法

が理解できました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

九九を表示するシェルプログラム

はじめに

Bashプログラミングの小ネタとして作成しました。
第4弾です。

九九の表を表示する

ソース

#!/bin/bash

ans=0
spc=' '

for i in $(seq 1 9)
do
  for j in $(seq 1 9)
  do
    ((  ans = $i * $j ))
    printf "%2d" $ans
    echo -e "${spc}\c"
    if (( $j == 9 ))
      then
      echo #改行させる
    fi
  done
done

printfを使って、1桁のときも強制的に2桁になるようにしました。
数字が連続すると見づらいため、各値の間に空白を入れました。

実行結果

$ ./kuku.sh
 1  2  3  4  5  6  7  8  9
 2  4  6  8 10 12 14 16 18
 3  6  9 12 15 18 21 24 27
 4  8 12 16 20 24 28 32 36
 5 10 15 20 25 30 35 40 45
 6 12 18 24 30 36 42 48 54
 7 14 21 28 35 42 49 56 63
 8 16 24 32 40 48 56 64 72
 9 18 27 36 45 54 63 72 81

おわりに

このプログラムを作成することで

  • 繰り返し構文
  • printfコマンド
  • (( ))を使用した計算
  • Bashのお作法

が理解出来ました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FizzBuzz問題をシェルプログラムで作成してみる

はじめに

Bashプログラミングの小ネタとして作成しました。
とある事情で急ピッチで記事を書いています。
ちなみに今回第3弾となります。

FizzBuzzとは

FizzBuzzに関してはこちらを確認ください。
1から順にカウントアップし、

  • 3で割り切れるときは「Fizz」を表示
  • 5で割り切れるときは「Buzz」を表示
  • 両方で割り切れるときは「FizzBuzz」を表示

といったことをします。

ソース

#!/bin/bash

echo -n "Please input number => "
read num

for i in $(seq 1 ${num})
do
  if (( $i % 3 == 0 && $i % 5 == 0 ))
  then
    echo "FizzBuzz"
  else if (( $i % 3 == 0))
    then
      echo "Fizz"
    else if (( $i % 5 == 0 ))
      then
        echo "Buzz"
      else
      echo $i
      fi
    fi
  fi
  sleep 1
done

実行結果

$ ./fizzbuzz.sh
Please input number => 15
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz

終わりに

3の倍数と3の文字列があるときにahoになるプログラムを応用させれば作れますね。

このプログラムを作成することで

  • アルゴリズム
  • 条件式
  • 条件演算子
  • readコマンド

が理解できました。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む