それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

ssh の .ssh/config 場所を変える。

ssh の鍵の場所を変える。ために.ssh の場所を変えたい。

ログインを許可していないユーザー (www-data, backup,gitlab-wwwなど)のssh の設定場所にいつも苦労する。

~/.ssh を変えたいと思った。→できない

ssh のデフォルトディレクトリの.ssh は、設定で変えられないんですね。

~.ssh の場所はデフォルで固定のようですね。将来のアップデートで変わるんだろうかと思ったけど、今のところ出来ないってことはセキュリティ懸念とかで固定されてるということでしょうね。

man ssh で調べてみる。

man ssh_config 見た感じでは、変えられないんですよ。

他の方法を探してみる。

そこで、他の方法をあれこれ考えてみる。

  • .ssh/id_rsa/.ssh/known_hosts なら変えられる。
  • .ssh/config は include が使える。
  • git 関連なら GIT_SSH_COMMAND を使え

代替方法は、上記が候補に上がる。

IdentityFile / UserKnownHostsFile などは変えられる。

.ssh/config の場所を変えることは出来ないが、

グローバル設定 /etc/ssh/config を使えば、デフォルトのファイルの場所を変えられる。

たとえば、次のファイルを変えられれる。

  • UserKnownHostsFile -- ~/.ssh/known_hosts
  • IdentityFile -- ~/.ssh/id_rsa

グローバル設定に書いておけば、個人用ファイルを気にせずにかくことができる。

設定例 /etc/ssh/ssh_config

Match user www-data 
  UserKnownHostsFile  /etc/confings/www-data/.config/.ssh/known_hosts
  IdentityFile   /etc/confings/www-data/.config/.ssh/id_rsa

~/.ssh/config は変えられない。→ include で代用

~/.ssh/config を変えられないが、 include は使える

それですね。そうですね。include も一つの方法でした。

設定例。

touch /etc/confings/www-data/.config/.ssh/config
echo  Include  /etc/confings/www-data/.config/.ssh/config  >  ~./ssh/config

Includeを使うことで、ユーザの空間ではなく、グローバルな空間に置く事ができる。

変えたいときって、どうせGitでしょ?

ssh の設定を変えたいときって、git cloneや git を使った CI/CDとかでしょ? GIT_SSH_COMMAND を使えばいいと思うよ。

export GIT_SSH_COMMAND="ssh -i ~/.ssh/id_rsa_example" 
git clone example

ci の yaml環境変数を書いておけば、ほとんど場合のCI/CDでの自動テストと自動ビルドのようなgit の鍵トラブルは軽減できますよね。

参考資料

Laravel の通知でカスタムチャネルとカスタム通知を作ってみる

Laravel の通知でカスタムチャネルとカスタム通知を作ってみる

今回の目標laravelの通知を自前で作る。

Laravelのマニュアルを読んでも、スッキリわからなかったので、一度作ってみることにした。

作ったもの

作ったものは整理して、次の場所に設置した。 https://github.com/takuya/php-laravel-slack-post

最初に知っておくこと

laravel で通知の種類(Slack/Mail/SMS)をチャンネル と呼ぶ。

laravel の通知の概要

オブジェクトに指定したチャンネル経由で、イベントの発生を通知する。

少しわかりにくいが、通知内容や通知イベントをクラス化しコードを管理できるようになっている。

「ユーザーに、新規ログインをメールで通知する」とか「ユーザーに、支払い失敗をSMSとメールで通知する」など。

イベント・通知内容によって通知先を切り替える。という運用になる。

通知するもの、通知されるもの、通知チャンネル(ドライバ)

「ユーザーに、新規ログインをメールで通知する」場合、

  • 通知される対象は User オブジェクト
  • 通知する対象は「新規ログイン」
  • 通知は「Mailチャンネル」経由。

このように、通知を3つの役割に分けて考えている。

ユーザーに通知する箇所の概念的構造。

分けておくこととで、通知が完結に記述できる。

通知オブジェクトの関係を開発者視点でコードを書くと次のようになる。

通知を送る例

<?php
$user->notify( new NewLoginDeviceDetected());

ここには、通知チャンネルは一切登場しない。

ただ、ユーザーにイベント発生を通知するんだな。とだけわかる。シンプルで素晴らしい(?)。

シンプルとはいえ、実際に通知をするのはどこでどうやってるのか全然わからない。メール・SMS・Slackなのか、通知チャンネルはコードへ登場しない。

通知するクラスは自分で作る。

例に出したNewLoginDeviceDetected クラスは、開発者が作る「通知クラス」である。artisan make:notification で作る

artisan make:notification NewLoginDeviceDetected

通知内容のクラスは過去形が読みやすい。

通知クラスは、「〇〇が変更された」「〇〇が失敗した」などイベント名にするといい感じになると思う。イベント名なので、英語動詞の過去形が相応しい。

先程の例だと NewLoginDeviceDetected ですね。

通知されるオブジェクトと、通知するイベント

通知されるイベント、通知受けるオブジェクトはそれぞれ指定のメソッドを生やす必要がある。

  • 通知するオブジェクトは use Notifiable;
  • 通知内容オブジェクトは、extends Notification

で作る。

通知受信オブジェクトの例

通知受けるオブジェクトは use Notifiable;を使う。

<?php
class User{
    use Notifiable;
}

Notifiable をつかってどのクラスにもメソッド追加できる。

interface でもいいとおもうけど、traitです。traitなので型指定ができず不便だけど我慢しましょう。

通知されるイベント(通知内容オブジェクト)の規約

通知されるオブジェクトは、extends Notification を使ってメソッドをもらってくる。こちらは継承なのでクラス型指定ができて便利ですね。

コードサンプル(Notificationをつかった通知作成例)

<?php
class NewLoginDeviceDetected extends Notification{
}

Notification を継承しておけばオッケ~です。

どのチャンネルで通知されるのか

どこ経由で通知するのか。これは、viaで指定する。

コードサンプル(Notification設定値より通知経路を指定する)

<?php
class NewLoginDeviceDetected extends Notification{
  public function via( $notifiable ):array {
    $default_available_channels = ['mail','slack','sms'];
    $channel=['slack']
    return array_intersect($channel,$default_available_channels);
  }
}

通知経路の指定は via()の関数本文内で行う。引数の$notifiable はtrait なので型指定ができない。

via()引数の $notifiableの設定から、チャンネルを絞ることもできる。 Userクラスが notifiableで渡されていてUserに設定があるならそれを使って通知経路(チャンネル)を指定することができる

コードサンプル(Userの設定値より通知経路を指定する)

<?php
class NewLoginDeviceDetected extends Notification{
  public function via( $notifiable ):array {
    $default_available_channels = ['mail','slack','sms'];
    return array_intersect(
        $default_available_channels,
        $notifiable->settings->channel
    );
  }
}

定義済みチャンネル(ドライバ)

via()がreturn しているのは String の配列です。

'main''slack' は、laravel に初期導入されてる予約名。

これをチャンネルのdriverというらしいですよ。

チャンネルにはドライバがあります。ややこしいですね。

通知経路を追加する。

Slackじゃなくて、discordがいいとか、流行りのMS Teamsがいいとか、追加した場合は。https://laravel-notification-channels.com/ にあるドライバをcomposer require すれば足せる。

自分で定義した通知経路(通知チャンネル・ドライバ)を使う場合

自作の通知経路を使うこともできる。そのときは、クラス名を名前空間付きで、returnすれば使える。Provierのような事前登録は不要。書けば動く。

<?php
class MyEventDetected extends Notification{
  public function via( $notifiable ):array {
      return [MyChannel::class];
  }
}

すでに定義済みのチャンネルで、足りる事が多いわけです。多分自分で作って使うことはないと思うのですが。

通知内容の文字列を整形(フォーマット)

通知されるオブジェクトと通知するオブジェクトの相互関係は少しわかった。

それでは、通知メッセージはどこでフォーマットされるのか。通知メッセージは、イベント名で作った通知オブジェクトが知っているという前提。

コードサンプル

toSlacke['slack'] に対応したテンプレートフォーマット。

<?php
    
class NewLoginDeviceDetected extends Notification{
  public function toSlack( $notifiable ){
    $message = new SlackMessage();
    $message
      ->from('通知ボット')
      ->to('#通知テスト用')
      ->content("新規ログインがありました");
    return $message;
  }
    
}

ドライバ名(mail/slack)と対応したメソッド(toMail/toSlack)と、それに対応したメッセージオブジェクト(MailMessage/SlackMessage)を使って通知の内容と本文を作成する。

通知内容のクラス読んでも、to${DriverName}() の名前は予測不可能だし、引数の $notifiable(通知を受けるオブジェクト)の型も予測不可能である。 何が来るか全く予想不能で少し使いづらそう。このあたり、今後のlaravel側の改善を期待したい。

通知チャンネルの具体的指定

メールやSMSのように宛先アドレスが1つしかない場合は、コードがシンプルで良き。

Slackにメッセージを投げる例

しかし、Slackのどのチャットルームにメッセージを投げるのか、など細かい指定はどこでやるのかパット見で分かりづらい。

通知を細かく設定する工夫

ここまで、見た来た結果、通知内容と通知経路は1対1で管理したほうがコードの見通しがよく、via で複数のチャンネル名を返却するのは本当に同じものを通知するとき以外は避けたほうが良さそう。

HTMLにするなど、整形が挟まるときは別々にしたほうが管理が楽になるでしょう。通知オブジェクトに細かい指定を作るのが良さそう

<?php
    
class SlackMyRoomNotification extends Notification {
    
}
class SendtoAdminMailNotification extends Notification {
}
interface toSlack {
    public function toSlack($notifiable);
}
interface toMail {
    public function toMail($notifiable);
}
class NewLoginDetectedToSlack extends SlackMyRoomNotification  implements toSlack {
    
}
class NewLoginDetectedToMail extends SendtoAdminMailNotification implements toMail {
    
}

「型」にこだわる必要はないと思うのですが。PHPだしある程度の型に関する寛容性は許しても良さそうなんだけど。

開発環境のツールでメソッド補完をしたいとか、引数の型チェックをしたいとか細かい要望を入れていると本当に難しい。

通知チャンネルの自作の懸念点

ここまで、いろいろ見てきたが 自作通知チャンネルに関するいくつかの懸念点が出てくる

  • toSlackでフォーマット時に$notifiableの設定を使いづらい。
  • 通知されるオブジェクトがないとき、どうするのか。
  • 自作の通知経路はinterfaceもtraitもないので、型指定が不便。
  • toSlack/toMailのようなフォーマットの型指定が不便。

なので、Laravel提供のドライバに併せてフォーマット範囲と定数を指定する必要がある。

自作で通知チャンネルを追加すると、汎用性は捨てて、作り捨てになる感じなりそうです。

自作で通知チャンネルを作ってみる。

自作通知チャンネルを作ってみる。

laravel デフォルトの slack 通知チャンネルは、Webhookを使うので、webhook の管理が煩雑になるので、個人のAPIキーをつかってBot作って投稿したい。

自作通知チャンネルで用意したクラス。

通知を作るのに、クラスが4つ必要ですね。ちょっとした通知なのに大変だ。

  • class SlackApiPostMessage / Slack API を叩いてメッセージを送るクラス
  • class SlackRoom / use Notifiable; された「通知を受け取るオブジェクト」
  • class SampleNotification/ extends Notification された通知内容のオブジェクト
  • class SlackApiChannel / send を実装した、通知するチャンネルオブジェクト
  • class TestSlackMessage / extends Command して artisan から実行

slack API の準備

APIトークンを取得

Slackでは、APIトークンを用いて、とてもかんたんにメッセージを取得、メッセージの投稿ができる仕組みがある。

webhook に比べてTOKENのほうが管理が楽なので私はこちらが好きなのです。

また、Slackの投稿は、Curlでぱぱっとできるので、投稿用URLを作っておけば再利用もかんたんです。

laravel なのでcurkを直接使わずに、Guzzleを使います。

slack の api トークンを取得して、configへ

https://api.slack.com/apps/
  • 自分のSlackのAppのWebページを開く
  • Create an app → full scratch → 名前とワークスペースを決める、
  • app を作ったら、Botを選ぶ。
  • App Homeから Botユーザ名を決める。
  • Bot に Scope を追加
  • Scope は chat:writeまたはchat:write.customize
  • スコープ追加したら、Workspaceにインストール
  • 最後に、書込み可能な、Tokenを作る。

TOKEを設定に保存

laravel の設定は、.env から取り出すのが流儀らしい。

config/slack.php

return [
  'token'=>env('SLACK_TOKEN'),
];

TOKENを環境変数に追加

.env に環境変数として追加する。

.env

SLACK_TOKEN=xoxb-123456-9876543-0heWmS

設定を再キャッシュする

artisan cache:clear

Slack の投稿をテストする。

投稿を送信するのに、わざわざサーバーボタンを作るのは煩わしいので、コマンドから叩く。

artisan make:command SampleSlackMessage

SampleSlackMessage.php

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;

class SampleSlackMessage extends Command {
  
  protected $signature = 'test:slack_token';
  
  /**
   * Execute the console command.
   * @return int
   */
  public function handle() {
    $cli = new \GuzzleHttp\Client();
    $res = $cli->request(
      "POST",
      'https://slack.com/api/chat.postMessage',
      [
        'form_params'     => [
          'token'   => config('slack.token'),
          'channel' => '#通知テスト用',
          'text'    => '書き込みテスト',
        ],
        'allow_redirects' => false,
      ]);
    $ret = $res->getBody()->getContents();
    
    return true;
    
    return 0;
  }
}

チャットルームに送信してみる。

artisan test:slack_token

無事に投稿できたらSlackのトークンは準備完了です。

SlackAPIを叩く汎用をクラスを作る。

tokenが無事に作れたので、SlackAPIを呼び出すクラスを作っておきます。

mkdir -p app/Services/Slack
touch -p app/Services/Slack/SlackApiPostMessage.php

SlackApiPostMessage.php

<?php
namespace App\Services\Slack;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Notifications\Messages\SlackMessage;

class SlackApiPostMessage {
  
  /**
   * @var string
   */
  protected $endpoint;
  /**
   * @var \Illuminate\Config\Repository|\Illuminate\Contracts\Foundation\Application|mixed
   */
  protected $token;
  /**
   * @var string
   */
  protected $channel;
  /**
   * @var string
   */
  protected $content;
  
  /** @var SlackMessage */
  protected $message;
  
  public function __construct() {
    $this->endpoint = 'https://slack.com/api/chat.postMessage';
    $this->token = config('slack.token');
  }
  
  public function content( string $message ) {
    $this->content = $message;
    
    return $this;
  }
  
  public function to( string $channel ) {
    $this->channel = $channel;
    
    return $this;
  }
  
  public function send() {
    $this->send_to_api();
    
    return $this;
  }
  
  protected function send_to_api() {
    
    $params = $this->jsonBuilder();
    try {
      $cli = new Client();
      $res = $cli->request(
        "POST",
        $this->endpoint,
        [
          'form_params'     => $params,
          'allow_redirects' => false,
        ]);
      $ret = $res->getBody()->getContents();
      return true;
    } catch (ClientException $e) {
      return false;
    }
  }
  
  protected function jsonBuilder(){
    $params = $this->message_to_paramters();
    $params = array_merge($params,array_filter([
      'token'=>$this->token,
      'channel' => $this->channel,
      'text'    => $this->content,
    ]));
    return $params;
  }
  protected function message_to_paramters() {
    $message = $this->message;
    $optionalFields = array_filter(
      [
        'channel'      => data_get($message, 'channel'),
        'icon_emoji'   => data_get($message, 'icon'),
        'icon_url'     => data_get($message, 'image'),
        'link_names'   => data_get($message, 'linkNames'),
        'unfurl_links' => data_get($message, 'unfurlLinks'),
        'unfurl_media' => data_get($message, 'unfurlMedia'),
        'username'     => data_get($message, 'username'),
      ]);
  
    return array_merge([
        'text' => $message->content,
        //'attachments' => $this->attachments($message),
      ],
      $optionalFields);
  
  }
  
  public function setMessage( SlackMessage $message ) {
    $this->message = $message;
  }
}

通知チャンネルをつくる

ここからが大変な、通知チャンネルの作成ですね。TOKENとSlack投稿がわかっただけで、まだ何もクラスを作ってません・・・

  • class SlackApiPostMessage / Slack API を叩いてメッセージを送るクラス
  • class SlackRoom / use Notifiable; された「通知を受け取るオブジェクト」
  • class SampleNotification/ extends Notification された通知内容のオブジェクト
  • class SlackApiChannel / send を実装した、通知するチャンネルオブジェクト
  • class TestSlackMessage / extends Command して artisan から実行

通知を送る箇所を作っておく

通知を、実際に送る箇所はこの様になる。

$room = new SlackRoom('#通知テスト用');
$room->notify(new SampleNotification('通知内容メッセージとか'));

通知を送る箇所を、コマンドとして作る

artisan make:command TestSlackMessage

TestSlackMessage

class TestSlackMessage extends Command {
  protected $signature = 'test:slack_notification';
  public function handle () {
    $room = new SlackRoom('#通知テスト用');
    $room->notify(new SampleNotification('通知内容メッセージとか'));
    
    return 0;
  }
}

通知を受け取るクラスを作る

通知を受け取るクラスは、UserなどEloquent Model にすることが多いと思うが、今回は汎用性を考えて、SlackRoomという名前にして、Slackのチャットルームが通知を受け取るという流れになるようなクラスの相互関係の設計とする。

artisan make:model '\App\Models\SlackRoom'

SlackRoom.php

class SlackRoom {
  
  use Notifiable;
  
  /** @var string */
  protected $channel_name;
  
  /**
   * SlackRoom constructor.
   * @param $channelName_in_slack
   */
  public function __construct( $channelName_in_slack ) {
    $this->channel_name = $channelName_in_slack;
  }
  
  /**
   * @return string
   */
  public function getChannelName():string {
    return $this->channel_name;
  }
}

通知チャンネルを作る

mkdir -p app/Channels 
touch -p app/Channels/SlackApiChannel.php

SlackApiChannel.php

namespace App\Channels;

use Illuminate\Notifications\Notification;
use \App\Services\Slack\SlackApiPostMessage;

class SlackApiChannel {
  
  public function send( $notifiable, Notification $notification ) {
    
    
    $formatter = 'toSlack';
    $cli->content('ここはメッセージ')
      ->to('#通知テスト用')
      ->send();
    $cli->send();
    
  }
}

通知内容クラスを作る

通知されるオブジェクトに対して、通知される内容を示すオブジェクトを作る

artisan make:notification SampleNotification

SampleNotification.php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;

class SampleNotification extends Notification {
  
  use Queueable;
  public function via( $notifiable ):array {
    return [SlackApiChannel::class];
  }
}

通知する。

すべてができたら、 notification /notifiable を使って通知する。

artisan test:slack_notification

全体の流れ

  • SlackRoom クラスが notify する
  • notify されるのは、 SampleNotification クラス
  • SampleNotification が SlackChannel クラスを返す。
  • SlackChannel クラスの send が実行される
  • send 中で、SlackAPIを呼び出す。

この間に受け渡されるのはSampleNotificationインスタンスです。

SampleNotification内部で、SampleNotification自身がSlack用・Mail用に自分のToStrngを用意しておく、しかし、自作の場合は、toXXXは存在せず呼び出されない。

メリットは?

コードがスッキルする。Notificationをクラス別につくれば、再利用しやすい。

逆に、通知経路が一つしかなく、通知するべき内容もかぎられているのであれば、そこまで無理して使う必要はないかもしれない。

sshのサーバーのホスト鍵を取得する・調べる。

ssh サーバーのホスト鍵を取得する。

SSHのホストキーを調べる

ssh-keyscan  -t rsa 192.168.2.1

ホストのキーを取得すれば、circleCIやgitlabCI などCI/CDのSSHの自動化のときホスト鍵を無視する設定をせずに済む。

ホスト鍵をサーバー内の設定から調べる。

Debian/Ubuntuの場合、ホストの鍵の公開鍵は、次のところに設置されている。

cat /etc/ssh/ssh_host_rsa_key.pub

known_hosts から取り出せばいいのでは?

それが取り出せないんですよね。known_hostsは初期設定ではハッシュ化されているので、パッと見てどのサーバーの鍵かわからない。

参考資料

https://serverfault.com/questions/321167/add-correct-host-key-in-known-hosts-multiple-ssh-host-keys-per-hostname

debianのphpでapcuを有効にする。

APCuが有効にならない。

sudo -u www-data php occ
An unhandled exception has been thrown:
OC\HintException: [0]: Memcache \OC\Memcache\APCu not available for local cache (Is the matching PHP module installed and enabled?)

清く正しくdebian提供の、コマンドphpenmodでモジュールを有効にする。

# phpenmod apc

apc のモジュールはロードされている。

ls -l /etc/php/*/*/*apc*
-rw-r--r-- 1 root root  31 Nov  4  2018 /etc/php/7.3/mods-available/apcu_bc.ini
-rw-r--r-- 1 root root 109 Jul  5 15:14 /etc/php/7.3/mods-available/apcu.ini

しかし、有効にならない。

sudo -u www-data php occ
An unhandled exception has been thrown:
OC\HintException: [0]: Memcache \OC\Memcache\APCu not available for local cache (Is the matching PHP module installed and enabled?)

php -i で状況を見る。有効にならない・・・

# php -i | grep -i apcu

/etc/php/7.3/cli/conf.d/20-apcu.ini,
/etc/php/7.3/cli/conf.d/25-apcu_bc.ini
APCu Version => 5.1.17
apcu
APCu Support => Disabled
APCu Debugging => Disabled

apc 関連のphp.iniが欠損していると気づく。マジか。

cat <<EOF  >> /etc/php/7.3/cli/conf.d/20-apcu.ini

[apcu]
apc.enabled=1
apc.shm_size=32M
apc.ttl=7200
apc.enable_cli=1
apc.serializer=php

EOF

APCuが有効になった。

php -i | grep -i apcu
/etc/php/7.3/cli/conf.d/20-apcu.ini,
/etc/php/7.3/cli/conf.d/25-apcu_bc.ini
APCu Version => 5.1.17
apcu
APCu Support => Enabled
APCu Debugging => Disabled

結論

debianphp-apcu のモジュールでは apc.enabled = 1 が欠損している。

debian 系の php-mods のインストールには気をつけろ。

今回は少し古いdebianphpでメンテナンスをしていたので、最新版では治ってるかもしれないが。十分に気をつける必要がある。

nextcloud でまた起きた(2022-05-12)

debian をbullseyeにアップデートしたら、このエラーが再現して、nextcloud が死んだ

Internal Server Error

The server encountered an internal error and was unable to complete your request.
Please contact the server administrator if this error reappears multiple times, please include the technical details below in your report.
More details can be found in the server log.

php-fpm がエラーになり、nginxが500を返すようになった。

sudo apt install php8.0 php8.0-fpm \
 php8.0-apcu \
 php8.0-xsl \
 php8.0-zip \
 php8.0-mbstring \
 php8.0-curl \
 php8.0-gd \
 php8.0-imagick \
 php8.0-sqlite3 \
 php8.0-redis \
 php8.0-mysql \
 php8.0-intl \
 php8.0-mcrypt \
 php8.0-memcache \
 php8.0-bcmath \
 php8.0-gmp \
 libmagickcore-6.q16-6-extra \

をして、phpenmodをした

phpenmod -v 8.0 apcu

これで生き返ったと思う。

Google Apps Scriptで、セルのK3の参照を出す。カラムの番号( col ) をアルファベットの参照に変える

ColumnとAddressの相互変換

K3 をはそのまま取得できるが 逆が難しい。

getRange( 'K3' )

getRange でアルファベットを使った、相対(絶対)参照をつかってスプレッドシートの領域を取れるのだが、逆に、セルを参照形式に変換するのが、頭を悩ませた。

K3 セルを取るには、どうすればいいんですか?

getRange( 3,10 ) //=> 'K3' にしたい

なのだけど、colum K = col:10 を変換するのが大変。アルファベットのA-Zまでならいいけど、AA-ZZまでくるともう大変だった。

Column番号を、アルファベットに変更

アルファベットの「文字」に変換する。適当なセルに一時的に=ADDRESS(3,10,4) を書き込めば K3が取れる

  findStartColLetter(sheet,col) {
    let tmp = sheet.getRange(1000, 1, 1, 1);// 適当な
    tmp.setValue('=ADDRESS(3,' + col + ',4)')
    let a = tmp.getDisplayValue();
    tmp.clear();
    return a[0];
  }

文字にするには、とりあえず ADDRESS 関数に掛けるのが速いのだが。ADDRESS関数を使った結果を取らないといけない。でもAddressに相当するGAS の関数が見当たらない。仕方ないので、ADDRESSを適当なセルに書き込むことに。

なぜアルファベットのカラム名が必要なのか。

getRange で、数字でアクセスできるのに、なぜ文字列を使ったセル参照名に変える必要があったのか。 それは、条件付き書式の計算である。

条件付き書式を読みやすく指定する。

条件付き書式に AddressやINDIRECTを使うと、うまく動作しなかったのである。また関数が増えるとあとで読んだときにわかりくいのである。

その他のGASの記事

Goole App Script ( GAS ) を始める。記事一覧 - それマグで!

Gitのリモートブランチをcloneする。

git の リモートブランチをclone したい

直接 clone できるわけじゃないけど、新規でclone する場合は結構楽に行える。

いつも流れ作業でやってるし過去にも書いてるんだけど。誰かに伝えるために改めてメモ。

作業の流れ

最初に、メインなブランチ(master)を clone する。 その後にリモートブランチをcheckout する。

作業コマンド

全体の作業の流れはこんな感じ。

git clone ${REPO_URL}
cd ${REPO_DIR}
git fetch 
git checkout -b ${BR_NAME} origin/${BR_NAME}

作業例

既存フォルダがあれば消す。

takuya@osx:~/Desktop$ rm code -rf

clone する

clone した時点では、master(main) ブランチ

takuya@osx:~/Desktop$ git clone git@ssh.mygit.example.com:repo/sample-/code.git
Cloning into 'code'...
remote: Enumerating objects: 413, done.
remote: Counting objects: 100% (413/413), done.
remote: Compressing objects: 100% (143/143), done.
remote: Total 16630 (delta 315), reused 302 (delta 247), pack-reused 16217
Receiving objects: 100% (16630/16630), 98.06 MiB | 13.38 MiB/s, done.
Resolving deltas: 100% (5694/5694), done.
Checking out files: 100% (832/832), done.

git フォルダ内部へ移動

takuya@osx:~/Desktop$ cd code

リモートブランチの状態を調べる

takuya@osx:~/Desktop/code$ git fetch
takuya@osx:~/Desktop/code$ git branch -r
  origin/HEAD -> origin/master
  origin/deploy-test
  origin/master
  origin/staging

リモートブランチをチェックアウト

takuya@osx:~/Desktop/code$ git checkout -b staging origin/staging
Branch 'staging' set up to track remote branch 'staging' from 'origin'.
Switched to a new branch 'staging'

チェックアウト結果を調べる。

takuya@osx:~/Desktop/code$ git branch
  master
* staging

ポイント

git ブランチは、ローカルとリモートで別々に存在します。

リモートのブランチをローカルでチェックアウトして使います。

チェックアウト時に、ローカルで変更(差分)があると、コンフリクトが発生したり、自動マージが走ったりします。注意してください。

lxc でCentOSのコンテナを起動する

centos をぱぱっと作る

LXCでCentOSのコンテナを起動して動作させる。

docker と違い ちゃんとinit.d / systemd が起動した centos なので実験・テスト環境にはとても楽。

LXD はほんと、ちょっとしたコツを覚えれば快適に実験環境を作れる。

centos を lxc で作成する

lxc launch images:centos/8 

名前は docker のように適当な単語を使って名付けられる。

自分でコンテナを名付けたいとき

lxc launch images:centos/8 my-example-cent8

ログインする

lxc shell my-example-cent8

名前がわからないときは、 lxc list  で起動中の一覧を取得できる。

centos を探す

lxc で 起動できる centos を一覧するには次のようにする。

lxc image list images:centos

cent / fedra などの起動

2021-06-17 lxc の記事をいくつか書いていたが centos や fedra についてだけ書いた記事を作ってなかったのでまとめ直した。

関連資料

https://takuya-1st.hatenablog.jp/entry/2020/09/11/150007

Goole App Script ( GAS ) を始める。記事一覧

Google Apps Script をはじめました。

GoogleAppScriptを始めたときに、思い通りのコードが書けるまで、四苦八苦しながら調べたことをまとめて記事にしています。

おもに、ハローワールドを実行し、実行方法を調べています。

また、その次にGASをファイルに分けたりgitで管理するとか、コードをいかに管理するかという視点が多いですね。

記事一覧

GAS はソコソコ枯れたツール

登場から随分時間が立つので、Google Apps Scriptはソコソコ情報も充実している。

そのため、わからないことを調べたら出てくるのですが。E○cel V○Aのような、いかがでしたかサイトの、検索汚染が激しい。

そこで、始めてから、コードを実行し、ファイルに分割し、Classに分割し、git 管理するまでを記事にまとめておいた。

表記揺れ

後で気づきました、Google Apps Script が正式名称ですが、google app script とずっと書いてしまっています。

参考資料

Goole App Script ( GAS ) の基本的な操作方法。18. clasp run でコンソールから実行

clasp run で ローカルからGAS実行

clasp run をつかえば、コマンドからGASを実行できます。

f:id:takuya_1st:20210608021310p:plain

clasp コマンドをうまく使えば便利かもしれないので、使い方を見ておく。

全体の流れ

結構手順が多いのです。

  • clasp コマンドをインストール
  • GASプロジェクトを設定
  • GCPプロジェクトを作成設定
  • GASとGCPを紐付け
  • clasp と GASを紐付け・認証
  • clasp に GCPを紐付け・認証
  • clap run

run を使うまでの手順が、煩雑で多いのです。OAuth関連の設定が多くてね。

clasp run は GCP にリクエストを投げ、GCPが GAS api を叩き、最新のコードを実行し結果を返してくれます。

clasp インストール

npm で clasp をインストールします。

npm install -g @google/clasp

GAS プロジェクト作成

https://script.google.com/ にアクセスして、プロジェクトを新規作成。

f:id:takuya_1st:20210608002540p:plain:w300

GCP プロジェクトを新規作成

GCP コンソールにアクセスして、プロジェクトを作成

GCP で作って保存するもの

GCPのコンソールでは、次の情報取得とAPI有効化をやります。

  • 必要情報の取得
    • プロジェクトID
    • プロジェクト番号(int)
    • OAuthクライアントのJSON
  • APIの有効化
    • apps scripts API の有効化

プロジェクトの作成と保存は、煩雑なので記事の末尾にスクショ付きで書いておきます。→ GCPプロジェクトの手順

GAS に GCP を紐付け

プロジェクト番号(数値)をGASに設定する

プロジェクト→ 設定

Google Cloud Platform(GCP)プロジェクト番号(数字)を貼り付ける。

f:id:takuya_1st:20210608005925p:plain:w320

clasp とGASを紐付け。

clasp login は終わっているものとします。

clone よる紐付け。

mkdir sample && cd sample
clasp clone ${スクリプトID}

または、create による紐付け

create → standalone でローカルで新規作成し、リモートへpush します。

mkdir sample && cd sample
clasp create myGas
clasp push

claspプロジェクトと GCP を紐付け

ローカルプロジェクトを、GCPと紐付けします。

GCPでダウンロードした認証情報JSONをプロジェクトへ移動

GCPから取得した認証情報JSONをプロジェクトへ

JSONは、GCP→ 認証情報→ クライアント→ダウンロードボタンでダウンロード。

clasp_project_dir=~/sample
mv client_secret_xxxx2697-xxxxonbxxxj.apps.googleusercontent.com.json \ 
${clasp_project_dir}/creds.json

clasp に projectIDを登録

clasp コマンドでプロジェクトに紐付ける。

GCP で作成したプロジェクトID(英数字名前)を入れる。

GCP_PROJECT_ID=gas-sample-001
clasp setting projectId ${GCP_PROJECT_ID}

json からプロジェクトを認証

json認証情報を使って、プロジェクトをOAuthする。

 clasp login --creds creds.json

ここでのログインは、プロジェクトがGCPへログインする。

ブラウザでOAuth

ブラウザが起動するので、GoogleアカウントでGCPのアカウントでログインして認証する。

終わったら次のような画面になる。

f:id:takuya_1st:20210608011412p:plain

コードを書く。

エディタを開き。関数を作り return を書く。忘れずにreturn を書く。

f:id:takuya_1st:20210608011604p:plain

return を書く理由は clasp run 実行後にコンソールに表示されるのが、関数の戻り値だから。

リモートへ送る

ローカルで作成したコードをscript.google.com へ push する。

clasp push 

デプロイ(公開する)

GASのプロジェクト・ページへ移動して、デプロイを作る。

デプロイを作成

GASのプロジェクト画面→デプロイ→新規作成→歯車→実行可能API

f:id:takuya_1st:20210608012202p:plain

clasp run 実行する

ようやく、本題の clasp run が出来ます。

clasp run

実行結果(戻り値)

実行すると、関数の戻り値が表示されます。

f:id:takuya_1st:20210608012628p:plain

実行結果(Console.log)

console.log で出力した、実行ログは、clasp logs コマンドで確認します。

f:id:takuya_1st:20210608012852p:plain

コードを更新して実行

次回以降は、push && run を繰り返せばいい。

clasp push 
clasp run myFunction 

clasp runは dev モードで動くので、push されたコードが常に実行される。

run 遅い

せっかくここまで設定したけど、push && run の clasp が遅い。表現したくないほど遅い。   

本当に遅いんですよ。 push && run をするのに待たされる。   

push に掛かる時間

f:id:takuya_1st:20210608022408p:plain

run に掛かる時間

f:id:takuya_1st:20210608022427p:plain

実行結果はスグ返るのに、終了が遅い。

実行自体はスグ終わります。その後なんの処理かわからないけど、終了処理で凄く待たされる。Ctrl-Cで中断したらプロジェクトの動作がおかしくなった。

clasp のclasp run 使えないかも。

CI/CD で回すならいいかも。

ローカルでコード書いて実行し、エラー見つけて修正、コード書いて実行みたいな使い方はとてもストレスなので使えないと思います。

自動実行をCI/CDでまわすなら、バックグラウンドで動くのでストレスなく使えるかもしれない。

git に push タイミングでGASにデプロイしてテストで実行する程度ならいいんじゃないですかね。

APEENDIX(GCPプロジェクト)

GCP プロジェクトの作成手順

GCP のプロジェクト作成で、GCP経由でGASのスクリプトを起動できるようにします。

保存するもの

プロジェクトを作成し、次のものを保存してclasp の設定に備える。

  • プロジェクトID
  • プロジェクト番号
  • 認証情報JSONの取得

設定するもの

GCP のプロジェクトで次を設定し、APIが利用できるようにする。

  • OAuth 同意画面
  • OAuth デスクトップ・クライアント
  • ライブラリ Gooogle App Script API

設定の流れ

設定は、次の流れで行う。

  • GCPコンソールにアクセス
  • プロジェクトを作成
  • プロジェクト番号とIDを保存
  • OAuth 同意画面の作成
  • OAuth クライアントを作成
  • JSONの保存
  • GAS Api の有効化

やることが多いです。

プロジェクトの新規作成

f:id:takuya_1st:20210608003002p:plain

プロジェクト情報の確認

ここで、ID(名前)と番号(数字)をメモります。

f:id:takuya_1st:20210608005753p:plain

OAuth 同意画面の作成

左上のメニュー → APIとサービス → OAuth同意画面

f:id:takuya_1st:20210608003200p:plain

同意画面は、必須項目を埋めるだけでいい。必須項目はメアドくらい。

自分しか使わないし。考えることはない。

OAuth認証情報の作成

左上のメニュー → APIとサービス → 認証情報→認証情報を作成

f:id:takuya_1st:20210608003309p:plain

クライアントIDを選ぶ

ここでは、クライアントを作るのでクライアントを選ぶ。

f:id:takuya_1st:20210608003331p:plain

種類はデスクトップアプリ

種類の選択で、デスクトップアプリを選ぶ

f:id:takuya_1st:20210608003357p:plain

JSONダウンロード

認証情報が作成されたら、デスクトップ用のJSONがダウンロードできる。

f:id:takuya_1st:20210608003454p:plain

API の有効化

プロジェクトで Google App Script API 有効にする。

ライブラリにゆく

f:id:takuya_1st:20210608003532p:plain

apps script api を有効にする。

f:id:takuya_1st:20210608003953p:plain

GCP 準備完了

これでGCPの準備は出来ました。次の情報が得られているはずです。

  • プロジェクトID
  • プロジェクト番号
  • 認証情報JSONの取得

これを、CLASPとGASに登録します。

プロジェクト番号(数字)は、GASへ登録

プロジェクトIDと認証情報は、clasp login で使います。

gcp 準備が完了したら、clasp をあとは実行するだけです。

GAS 目次

ひとまずここで筆を置きます。GASに関しては次が目次です。

Goole App Script ( GAS ) を始める。記事一覧 - それマグで!

Goole App Script ( GAS ) の基本的な操作方法。17. claspで GASをローカルからVisualStudioCode編集して補完し、git管理する。

f:id:takuya_1st:20210607213754p:plain

インストール clasp

clasp コマンドは @google/clasp で提供されています。 @google/clasp をグローバルにインストールしてclasp コマンドを使えるようにします。

npm install -g @google/clasp

npm なのでインストールは時間が必要です。

インストール確認

clasp コマンドがインストールされたかチェックしておきます。

which clasp #=> /usr/bin/clasp
clasp help

初期設定

インストールが終わったら初期設定です。google アカウントと紐付けます。

ログインしてOAuthします。

clasp login

scrpipt.google.com にログインして、プロジェクトにアクセスできるようにしなくてはいけません。login を実行してブラウザを立ち上げて、clasp コマンドにパーミッションを与えます。 ローカルホストでWEBが起動しブラウザ経由でOAuthします。

oauth 完了

f:id:takuya_1st:20210607214445p:plain

設定ファイル

Googleアカウントの権限付与したら、設定ファイル~/.clasprc.json が作られます。

$ ll  ~/.clasprc.json
-rw------- 1 takuya takuya 2267 Jun  7 21:44 /home/takuya/.clasprc.json

準備完了

これで、プロジェクトをローカルに取り込む準備ができました。

clasp clone

既存のプロジェクトをclone する。

まずは、既存のプロジェクトをデスクトップにコピーしてきます。

mkdir してから clasp clone

clasp clone コマンドでGASの一覧から、スクリプトをコピーできる。

サンプル
## プロジェクトフォルダをつくる。
mkdir myGas
cd myGas
mkdir src
## GASからコードを取り出す。
clasp clone 0wmjSXXXXXXXXXXsx98zZtcpljDBc
## 編集したら pushする
clasp push

フォルダは自動生成されません。

フォルダは作成されないので、さきにフォルダをつくり、clone します。 git clone のようにフォルダが自動生成されないので注意(大事なので2回書いています。)

clone 後は、ローカルファイルとして編集できます。編集が終わったら push します。

clasp push

push すればアップロードされアップデートされます。

clasp push 

clasp push でアップロードです。`ローカル→script.google.comへアップロード

プロジェクトIDの発見方法。

GASの「プロジェクト」には固有のプロジェクトIDが割り振られています。これを取得します。

アドレスの文字列をコピーします。

プロジェクトを開いたときのアドレスをコピーすればOKです。

https://script.google.com/home/projects/{ここ}/

複数アカウントGoogleログインしている場合はURLが異なります。

https://script.google.com/u/2/home/projects/{ここ}/

google サービスは複数アカウントのログイン時にhostname.google.com/u/{number}/ のようなアドレスになりますが、もうずっと10年以上複数アカウントの不具合が残ってます。今使ってるアカウントには注意しておきます。

プロジェクトの設定画面

プロジェクトの設定画面からもプロジェクトの固有IDを見つけることが出来ます。 f:id:takuya_1st:20210607214857p:plain

clone は時間がかる。

clasp の clone はすこし時間がかかります。辛抱強く待ってください。

ローカルで管理するメリット。

ウェブサイトで開発できるのに、わざわざローカルにコピーするメリットはいくつかあります。

  • git によるコード管理・属人化の防止
  • トランスパイラ利用
  • エディタ

git による管理。

ファイルがローカルになることで、git push 管理できます。git にすることで変更点を残しておけます。

cd CLASP_DIR
git init 
git remote add origin ssh://xxxx
git commit -m import 
git push 

これで、コードを管理しやすくなります。とくに共通コードをまとめて管理できるようになるはずです。

Google Driveからの独立

Google Driveから独立して管理できるので、個人のGoogle Driveやscript.google.com から独立し、自立できます。個人のGoogle Driveに依存しないので、ドキュメント類を残したり手順を標準化しやすくなります。

トランスパイラ利用(コンパイル)ができるようになる。

polyfill を使ったり TypeScript を書いたものを gs/js にトランスパイルすることで、記述を柔軟にできるようになって便利です。gas を typescript で書いたり reactできるようになって便利です。

外部ライブラリをまるっと取り込んでnpm の恩恵に預かれる。

エディタを選べて補完ももできる。

自由にエディタを選べるようになります。

コード補完をする。

次のパッケージを使えばコード補完もできるようになります。

npm install --save @types/google-apps-script

@types/google-apps-script が GASの補完などのファイル・タイプ定義ですね。

補完例

Visual Studio Code で GASを補完しながら書いている例です。completion は特に設定しなくても install するだけで大丈夫です。

f:id:takuya_1st:20210607221319p:plain

おまけ、clasp /git 管理は、 --rootDirをつける

claspを使ってGASをgit 管理するとき、clasp clone --rootDir を使いましょう。

cd project
mkdir src
clasp clone  --rootDir=src

--rootDir を設定することで、gas の管理が楽ちんになります。GASは全ファァイルをロードするので、うっかりすると必要のないファイルまでpushされ、GASロードされちゃいます。

なので --rootDir がないとき、 .claspignore で .git を無視する必要があります。そのために、 --rootDir を使います。必ずつけましょう。

またトランスパイラを通すときは、トランスパイラの出力フォルダ dist を 指定します。 --rootDir=dist ですね。

次回へ続く

長いので分割しました→次回

Goole App Script ( GAS ) の基本的な操作方法。 16. 専用サイトでGASプロジェクトを管理する。

GAS は Google drive

GASの一覧と管理は、Google Driveで行うのが基本になるみたいですね。

Google Driveのフォルダに、プロジェクトが作成される。

プロジェクトは固有IDを持ち、好きなフォルダに設置することができる。スプレッドシートからスクリプトエディタを開いたときは、スプレッドシートと同じフォルダに設置される。

スクリプトが増えてくると、スクリプトシートと紐付いているのを無視して管理したくなる。そのときに便利なのがプロジェクトを一覧するサイト。

google app script は次のサイトで一覧できる。

GASのプロジェクトファイルは、次のサイトでDriveに四散しているプロジェクトファイルを見ることができる。

https://script.google.com/home

自分のプロジェクトの一覧を見ることができる。

f:id:takuya_1st:20210607211718p:plain

タイマーの一覧も見れる。

トリガーで作ったタイマーも、プロジェクトを横断して確認できる。

f:id:takuya_1st:20210607212231p:plain

https://script.google.com/home でプロジェクト単体として存在できる。

https://script.google.com/homeで管理するのはプロジェクト単体な、プロジェクトである。スプレッドシートやスライドと紐付かず、独立したプロジェクトとしても作成できる。

ドキュメントから独立したプロジェクトの魅力

単体プロジェクトは、ドキュメントとペアにせず、単独のプロジェクトとして、作成管理できる。

そのため、テンプレートから新規ファイルを作るプロジェクトや、結果を新規ドキュメントに保存するようなプロジェクトを作成して管理しやすくなって便利ですね。

## 次回へ続く

長いので分割しました→次回

Goole App Script ( GAS ) の基本的な操作方法。15. GAS をスケジュールで実行する

GAS の実行方法の種類

GASを実行するには、いくつか方法があって、ボタンを押して実行、メニューから実行、実行ボタンを押す、HTMLで実行、スケジュールで実行、APIで実行がある。

分類すると次のようになる。

  • ドキュメント内イベントハンドラで実行
    • ボタンを押す
    • 開く・編集で実行
    • メニューから実行
  • HTML を使う。
    • HTMLを表示で実行
    • フォーム送信で実行
  • 単体で実行
    • タイマーで実行
    • APIで実行

今回は、タイマーで実行する方法を見ておく。

GoogleAppScript をタイマー実行する

GASはスケジュールで実行の設定ができる。スケジュール実行は、とてもかんたん。

トリガーを作る

スクリプトメニューから、トリガーを選択

f:id:takuya_1st:20210607150639p:plain

トリガーを追加

時刻でトリガーを追加する。

実行する関数と、実行する時間・日付をきめてトリガーを作成すればオッケ。

f:id:takuya_1st:20210607150620p:plain

便利ですね。

追加費用もなしで、スクリプトをタイマーで実行できるのはいいですね。

レンタルサーバーなどではcrontab などが必要で実行数が規制されたりするし、crontab/systemd を使うと設定に知識が必要なのに、GASは本当にかんたんに実行できる。

次回へ続く

長いので分割しました→ 次回

Goole App Script ( GAS ) の基本的な操作方法。14.スプレッドシートに追記する。

スプレッドシートに追記したい。

スプレッドシートのデータの範囲に、次の行を書くにはどうするのか。同じデータを連続して書き込むにはどうするのか。少し考えてみた。

セルに続けて書きたい。

セルの最終行に次行のレコードを書き込んでログのように記録を取りたい

次のように、続けて書き込みたい。

f:id:takuya_1st:20210605022853p:plain:w200

GASの例

function main(){
  addCell();
}
function addCell() {
  let app = SpreadsheetApp.getActiveSpreadsheet();
  let sh = app.getActiveSheet();
  let range = sh.getDataRange();
  let r = range.getLastRow();
  let c = range.getLastColumn();
  let nextCell = sh.getRange(range.getLastRow()+1,1,1,2);
  let data = [
    [getCurrentIp(),currentDateTime()]
  ]
  nextCell.setValues(data)

}
// データ
function getCurrentIp() {
  let ip = 'x.x.x.x'
  let url = 'https://api.ipify.org?format=json'
  let json = UrlFetchApp.fetch(url);
  let obj = JSON.parse(json);
  //ip = (obj) ? obj.ip : ip;
  return ip;
}
function currentDateTime(){
  let d = new Date()
  let str = Utilities.formatDate(d, 'Asia/Tokyo','yyyy/MM/dd HH:mm:ss')
  return str;
}

実行すると。

最初、空っぽの状態から、データがログのように書き込まれる。
f:id:takuya_1st:20210605021733p:plain:w200

f:id:takuya_1st:20210605021815p:plain:w200

コードについて。

今回使ったコードの冒頭部分について。

現在データが書き込まれている範囲を取る。

getDataRange は、CTRL-Aで選択して自動的に作られる選択範囲を取得する。

  let app = SpreadsheetApp.getActiveSpreadsheet();
  let sh = app.getActiveSheet();
  let range = sh.getDataRange();
  let r = range.getLastRow();
  let c = range.getLastColumn();

次の行の範囲を取る。

次の行を選ぶのでgetLastRow()+1 を使う。列は先頭からなので、1を入れる。(プログラミングになれた人は、ここで配列と同じ入れがちなので注意、セルは1から数えます。)

sh.getRange(range.getLastRow()+1,1,1,2);

getRange は矩形選択、Rectangleの描画と同じ

getRange は1,2引数で選択開始位置。(開始座標)
getRange は3,4引数で選択する個数。(縦横長さ)

getRange( startRow, StartCol, numOfRow, numOfCol) 

選択範囲にデータを貼り付け

選択範囲にデータを貼り付けするのは setValues を使う。

setValues([  [ COL_A, COL_B ]  ] )

setValue の引数は、ネストした多次元配列。

多次元配列には、行ごとにデータを入れる。

data = [
 [ "A1", "B2" ] //  1行目
 [ "A2", "B2" ] //  2行目
]

データの追記はよくやるので

データ追記はよくやるので、ぱぱっとできるといいな。

2021-06-07 追記

似たような方法に次のような方法がある。 getLastRow 関数を利用する。

getLastRow はデータ領域の最終行が返されるので、不定数のカラムを書き込むのであれば、getLastRowもいいと思う。

この記事では、行の下方向に決まったデータを追記するので、getDataRange() を使ってます。

getLastRow は次のペアで覚えておくと便利です。

sheet.getLastRow();
sheet.getLastColumn();

次回へ続く

長いので分割しました→次回

Goole App Script ( GAS ) の基本的な操作方法。13.スプレッドシートのセルの基本操作

前回の続き

前回までで、GASでコードを書いて実行する方法がわかった。

今回はセル操作

今回は、Spreadsheetの基本的な使い方を見ておく。

セルの取得=範囲の取得

EXCELでも同じ。知っていると思うけど知らないと混乱するので注意。

セルを取得するとは、範囲=1の選択範囲を作るということ。

範囲を選択する

let sps = SpreadsheetApp.getActiveSpreadsheet();
let sht = sps.getSheets()[0];
let rg  = sht.getRange("B5:B6");
g.activate();

範囲を選択するのに1つだけ選択したら、セルを選択。

let sps = SpreadsheetApp.getActiveSpreadsheet();
let sht = sps.getSheets()[0];
let rg  = sht.getRange("B6");
g.activate();

セルを取得

let sps = SpreadsheetApp.getActiveSpreadsheet();
let sht = sps.getSheets()[0];
let rg  = sht.getRange("B5");
rg.activate();

セルの値を取得

let sps = SpreadsheetApp.getActiveSpreadsheet();
let sht = sps.getSheets()[0];
let rg  = sht.getRange("B5");
rg.activate();
let val = rg.getValue();
console.log(val)  

セルの書式(表示形式)を取得

数値は、表示形式が重要なので、数値の表示形式を見ておく。

let fmt = rg.getNumberFormat();
console.log(fmt)

日付形式 yyyy/MM/dd 日付と時刻 yyyy/MM/dd H:mm:ss 時刻 HH:mm:ss

セルの値を更新

セルの値を更新して、数字の表示形式を入れていく。

  rg.setValue('2021年6月4日');
  rg.setNumberFormat('yyyy/MM/dd');

セルに背景を設定

  let sps = SpreadsheetApp.getActiveSpreadsheet();
  let sht = sps.getSheets()[0];
  let rg  = sht.getRange("B5");
  rg.setBackgroundRGB( 250,120,120 );

セルの背景色を解除

背景色を解除するのには、setBackgroundで null を設定する。 クリアでは、値ごとすべて解除される。

let sps = SpreadsheetApp.getActiveSpreadsheet();
let sht = sps.getSheets()[0];
let rg  = sht.getRange("B5");

rg.setBackground(null);

セルの枠線・ボーダーを設定

ボーダーは、範囲に対して設定する引数の順番に注意、

上下左右を設定する

let rg  = sht.getRange("B5");
rg.setBorder(true, true, true, true, false, false);

内側も含めてすべて設定する。

すべてを true にすると、全部設定できる。

rg.setBorder(true, true, true, true, true, true);

セルの枠線(ボーダー)をすべて解除

すべてを解除するには、false を設定する。

  rg.setBorder(false,false,false,false,false,false);

変更しない=null を設定する。

下だけ変更したいときのように、他を変更したくないときは、 null を渡す。

  rg.setBorder(null,null,true,null,null,null);

引数がどうしても多くなるので使うときに不便ではあるが、覚えておく必要がある。

セルのボーダーの枠線スタイルを決める。

SpreadsheetApp.BorderStyle.SOLID_THICK のように、名前空間の中に入れる。

  • DOTTED / 点線
  • DASHED / 破線
  • SOLID (* デフォルト) / 線
  • SOLID_MEDIUM / 太線
  • SOLID_THICK / 極太
  • DOUBLE / 二重線

引数は、8番目。

range.setBorder(top, left, bottom, right, vertical, horizontal, color, style)

極太線を設定する。

rg.setBorder(true, true, true, true,
    true, true, 
    null,
    SpreadsheetApp.BorderStyle.SOLID_THICK
    );

枠線の色を決める。

色をは HTML と同じ色指定。256色なRGBを #FFFFFF と同じく入れる。

rg.setBorder(true, true, true, true, true, true, 
    "#88AA00",
    SpreadsheetApp.BorderStyle.SOLID_THICK
    );

次回へ続く

長いので分割しました→次回

Goole App Script ( GAS ) の基本的な操作方法。12. キーボード・ショートカット

スクリプト・エディタのキーボードショートカット

実行 / Ctrl-R

  • 実行 / Ctrl -R / ⌘ -R
  • ログ切り替え / Ctrl - Enter / ⌘ - Enter

実行は、選択中の関数が実行される。

選択中の関数とはこれ

選択中の関数とは、このメニューで選択している関数である。

f:id:takuya_1st:20210604045521p:plain

カーソル位置の関数を実行してくれると楽なんだけど、毎回選択し直す必要があるみたい。

編集のショートカット

  • 補完 ctrl-space / ⌘ -Space
  • 単語補完 alt- / (スラ) / ⌘- /
  • コメント・トグル ctrl - / (スラ)
  • 行削除 ctrl -d / ⌘ - D
  • インデント TAB
  • アンインデント Shift-TAB
  • コードの整形 / Alt-Shift-F

補完中の操作

補完中の操作は、通常のIDEと同じ

f:id:takuya_1st:20210604050113p:plain:w280

  • 候補移動 矢印 ↑ ↓
  • 選択 TAB / Enter

タブで補完決定できるのはちょっと好き。

コードの整形もできる

選択範囲のコードの整形ができます。

f:id:takuya_1st:20210604152846p:plain

保存

  • カレントファイル保存 Ctrl - S / ⌘ - S
  • すべて保存 Ctrl-Shift-S / ⌘- Shift - S

キーボード・ショートカットの調べ方

エディタにフォーカスが存在するときに、F1を押せば、コマンドパレットが表示され、キーボードショートカットを見ることができる。

右クリックでメニューを表示

メニューを見れば、キーボードショートカットもわかる。

f:id:takuya_1st:20210604153009p:plain

コマンド・パレットでショートカットを見る。

右クリックから、コマンド・パレットを参照すれば、さらに機能を見ることができる。

コマンドパレットを参照すれば、以外に多機能で、こんなこともできるんだ!っていう発見が多いので、一度は見ておくこと。

f:id:takuya_1st:20210604153159p:plain

次回へ続く

長いので分割しました→ 次回