CHUWEI HiPad Proを買ったらがっかりペンタブレットだった件


スナドラ662で、メモリ8GB、ストレージ128GBというスペックにひかれてCHUWEI HiPad Proをペン付きで購入してみました。

8月5日に発送連絡があって、到着したのが8月17日でした。

追加送料払ってなかったのでもっと時間がかかるのかと思っていたら2週間かからないという予想外の到着でした。

ペン付きで買ったので2つ届きました。

裏面は綺麗な感じですね

添付のペンはHiPen H6とありました。

起動後の初期設定は普通のAndroidなので飛ばして、firmware updateを行います。

ここ、メッセージを読み飛ばしていたのですが、アップデート後の再起動でかならず下記の画面でブート失敗します。

画像

ボリュームの下ボタンを押して「Factory data Reset」を実行して初期化をする必要がある、ということです。

なので、ファームウェアアップデートが完了するまでGoogleアカウントの登録などの詳しい設定を行ってはいけない、ということですね。

さて、とりあえず原神を起動して様子見・・・

うーん・・・いまいち

次・・・ペンの動作がどうか確認。

手持ちにWacom Bamboo Inkペンがあったので、今回買ったHiPen H6を並べて見る。

だいたい同じサイズ。

画像

ペン先のサイズがちょっと違うっぽい(なお、Bamboo Inkのが斜めにみえるのは、曲げてしまってしまったため)

HiPad ProはMPP(Microsoft Pen Protocol)採用という話なので、Bamboo InkをMPPモードで電源を入れると使える様になる。

Bamboo Inkで書いた時と

HiPen H6で書いた時と比べると結構筆圧動作が違ってて興味深かったです。

・・・ここまではそんなに問題なさそうに見えますよね

ところが・・・

見ての通りに

ペンの動きに対して、描画が遅すぎる

この動作、CLIP STUDIOだけでなくKritaでも、筆圧検知自体は出来ているけど、遅延が酷い状態でした。

画像

よって、絵描き用途としてまったく向かない感じでした。

このCHUWEI HiPad Proですが、事前にAmazon PrimeがHDで見れる、というのもあったのですが、ChinaR「【CHUWI HiPad Proレビュー】WideVine L1認証済みのCHUWI HiPad ProはAmazonプライムビデオのHD再生に非対応(CHUWI HiPad Pro Don’t Support HD On Amazon Prime Video, Although Got WideVIne L1)」にあるように対応できてない、とかいう問題もあります。

とりあえず、うちのHiPad Proは2万円分のネタになってもらえるように、他の人に貸し出して楽しんでもらうつもりです

pythonのtwitterモジュールで特定ユーザの発言を取得する


twitterのspaceによる音声配信は、m3u8ファイルを使用してのhttpsによるaacファイルの配布という形で実現されている。

streamlinkにm3u8ファイルのURLを与えると音声ファイルが取得できるので、これを自動化できないか検討している。

まず第1歩として、指定したユーザのタイムラインでspace配信のURLがあった場合に検出できないかを確認。

単純にwgetやcurlで「curl -s https://twitter.com/niselog/」とやっても発言は拾えない。

python-twitterのマニュアルを見ながらpythonスクリプトを作成

#!/usr/bin/python

import os
import twitter

token='文字列'
token_secret='文字列'
consumer_key = '文字列'
consumer_secret='文字列'

t = twitter.Api(consumer_key=consumer_key,
        consumer_secret=consumer_secret,
        access_token_key=token,
        access_token_secret=token_secret)

for line in t.GetUserTimeline(screen_name="niselog"):
        print line

これを実行すると、下記の様な出力になる

-bash-4.2$ ./test3.py |tail -2
{"created_at": "Sat May 14 08:13:22 +0000 2016", "hashtags": [{"text": "\u30b1\u30eb\u30d9\u30ed\u30b9\u30d6\u30ec\u30a4\u30c9"}], "id": 731396977758339072, "id_str": "731396977758339072", "lang": "ja", "source": "<a href=\"https://about.twitter.com/products/tweetdeck\" rel=\"nofollow\">TweetDeck</a>", "text": "\u507d\u30ed\u30b0 for #\u30b1\u30eb\u30d9\u30ed\u30b9\u30d6\u30ec\u30a4\u30c9 \u306f\u30b1\u30eb\u30d9\u30ed\u30b9\u8d85\u4f1a\u8b70\u306e\u4e00\u89a7\u30da\u30fc\u30b8\u306b\u5bfe\u5fdc\u3057\u307e\u3057\u305f https://t.co/gDlRyiFWC3", "urls": [{"expanded_url": "http://tw5.niselog.jp/", "url": "https://t.co/gDlRyiFWC3"}], "user": {"created_at": "Mon Mar 01 05:51:23 +0000 2010", "default_profile": true, "default_profile_image": true, "description": "\u30c8\u30df\u30fc\u30a6\u30a9\u30fc\u30ab\u30fcPBW \u7121\u9650\u306e\u30d5\u30a1\u30f3\u30bf\u30b8\u30a2/\u30b7\u30eb\u30d0\u30fc\u30ec\u30a4\u30f3/\u30a8\u30f3\u30c9\u30d6\u30ec\u30a4\u30ab\u30fc\uff01/\u30b5\u30a4\u30ad\u30c3\u30af\u30cf\u30fc\u30c4\u3078\u306e\u643a\u5e2f\u5411\u3051\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u30b5\u30fc\u30d3\u30b9\u300c\u507d\u30ed\u30b0\u300d\u306e\u7ba1\u7406\u8005\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u3059\u3002 http://t.co/QMKlQjzjSI http://t.co/YEiNJUvGdU", "followers_count": 40, "id": 118604209, "id_str": "118604209", "listed_count": 5, "name": "niselog \u7ba1\u7406\u8005", "profile_background_color": "C0DEED", "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", "profile_image_url": "http://abs.twimg.com/sticky/default_profile_images/default_profile_normal.png", "profile_image_url_https": "https://abs.twimg.com/sticky/default_profile_images/default_profile_normal.png", "profile_link_color": "1DA1F2", "profile_sidebar_border_color": "C0DEED", "profile_sidebar_fill_color": "DDEEF6", "profile_text_color": "333333", "profile_use_background_image": true, "screen_name": "niselog", "statuses_count": 340, "url": "http://t.co/QMKlQjzjSI", "withheld_in_countries": []}, "user_mentions": []}
{"created_at": "Sat May 14 07:02:08 +0000 2016", "hashtags": [], "id": 731379051852505088, "id_str": "731379051852505088", "lang": "ja", "retweet_count": 2, "source": "<a href=\"https://about.twitter.com/products/tweetdeck\" rel=\"nofollow\">TweetDeck</a>", "text": "\u7121\u9650\u306e\u30d5\u30a1\u30f3\u30bf\u30b8\u30a2\u3001\u30b7\u30eb\u30d0\u30fc\u30ec\u30a4\u30f3\u3001\u30a8\u30f3\u30c9\u30d6\u30ec\u30a4\u30ab\u30fc\u5411\u3051\u306e\u507d\u30ed\u30b0 https://t.co/QMKlQjzjSI \u3067\u3059\u304c\u3001\u590f\u9803\u306b\u5b8c\u5168\u505c\u6b62\u3059\u308b\u4e88\u5b9a\u3067\u3059\u3002(URL\u306f\u6b8b\u308a\u307e\u3059\u304c)", "urls": [{"expanded_url": "http://niselog.jp/", "url": "https://t.co/QMKlQjzjSI"}], "user": {"created_at": "Mon Mar 01 05:51:23 +0000 2010", "default_profile": true, "default_profile_image": true, "description": "\u30c8\u30df\u30fc\u30a6\u30a9\u30fc\u30ab\u30fcPBW \u7121\u9650\u306e\u30d5\u30a1\u30f3\u30bf\u30b8\u30a2/\u30b7\u30eb\u30d0\u30fc\u30ec\u30a4\u30f3/\u30a8\u30f3\u30c9\u30d6\u30ec\u30a4\u30ab\u30fc\uff01/\u30b5\u30a4\u30ad\u30c3\u30af\u30cf\u30fc\u30c4\u3078\u306e\u643a\u5e2f\u5411\u3051\u30b2\u30fc\u30c8\u30a6\u30a7\u30a4\u30b5\u30fc\u30d3\u30b9\u300c\u507d\u30ed\u30b0\u300d\u306e\u7ba1\u7406\u8005\u30a2\u30ab\u30a6\u30f3\u30c8\u3067\u3059\u3002 http://t.co/QMKlQjzjSI http://t.co/YEiNJUvGdU", "followers_count": 40, "id": 118604209, "id_str": "118604209", "listed_count": 5, "name": "niselog \u7ba1\u7406\u8005", "profile_background_color": "C0DEED", "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png", "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png", "profile_image_url": "http://abs.twimg.com/sticky/default_profile_images/default_profile_normal.png", "profile_image_url_https": "https://abs.twimg.com/sticky/default_profile_images/default_profile_normal.png", "profile_link_color": "1DA1F2", "profile_sidebar_border_color": "C0DEED", "profile_sidebar_fill_color": "DDEEF6", "profile_text_color": "333333", "profile_use_background_image": true, "screen_name": "niselog", "statuses_count": 340, "url": "http://t.co/QMKlQjzjSI", "withheld_in_countries": []}, "user_mentions": []}
-bash-4.2$

unicode escapeという形式で文字が表示されているので読めない。

全体的にみてみるとJSON形式のデータになっているのでjqコマンドを通して見た。

-bash-4.2$ ./test3.py |tail -2|jq .
{
  "created_at": "Sat May 14 08:13:22 +0000 2016",
  "hashtags": [
    {
      "text": "ケルベロスブレイド"
    }
  ],
  "id": 731396977758339100,
  "id_str": "731396977758339072",
  "lang": "ja",
  "source": "<a href=\"https://about.twitter.com/products/tweetdeck\" rel=\"nofollow\">TweetDeck</a>",
  "text": "偽ログ for #ケルベロスブレイド はケルベロス超会議の一覧ページに対応しました https://t.co/gDlRyiFWC3",
  "urls": [
    {
      "expanded_url": "http://tw5.niselog.jp/",
      "url": "https://t.co/gDlRyiFWC3"
    }
  ],
  "user": {
    "created_at": "Mon Mar 01 05:51:23 +0000 2010",
    "default_profile": true,
    "default_profile_image": true,
    "description": "トミーウォーカーPBW 無限のファンタジア/シルバーレイン/エンドブレイカー!/サイキックハーツへの携帯向けゲートウェイサービス「偽ログ」の管理者 アカウントです。 http://t.co/QMKlQjzjSI http://t.co/YEiNJUvGdU",
    "followers_count": 40,
    "id": 118604209,
    "id_str": "118604209",
    "listed_count": 5,
    "name": "niselog 管理者",
    "profile_background_color": "C0DEED",
    "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
    "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
    "profile_image_url": "http://abs.twimg.com/sticky/default_profile_images/default_profile_normal.png",
    "profile_image_url_https": "https://abs.twimg.com/sticky/default_profile_images/default_profile_normal.png",
    "profile_link_color": "1DA1F2",
    "profile_sidebar_border_color": "C0DEED",
    "profile_sidebar_fill_color": "DDEEF6",
    "profile_text_color": "333333",
    "profile_use_background_image": true,
    "screen_name": "niselog",
    "statuses_count": 340,
    "url": "http://t.co/QMKlQjzjSI",
    "withheld_in_countries": []
  },
  "user_mentions": []
}
{
  "created_at": "Sat May 14 07:02:08 +0000 2016",
  "hashtags": [],
  "id": 731379051852505100,
  "id_str": "731379051852505088",
  "lang": "ja",
  "retweet_count": 2,
  "source": "<a href=\"https://about.twitter.com/products/tweetdeck\" rel=\"nofollow\">TweetDeck</a>",
  "text": "無限のファンタジア、シルバーレイン、エンドブレイカー向けの偽ログ https://t.co/QMKlQjzjSI ですが、夏頃に完全停止する予定です。(URLは残りますが)",
  "urls": [
    {
      "expanded_url": "http://niselog.jp/",
      "url": "https://t.co/QMKlQjzjSI"
    }
  ],
  "user": {
    "created_at": "Mon Mar 01 05:51:23 +0000 2010",
    "default_profile": true,
    "default_profile_image": true,
    "description": "トミーウォーカーPBW 無限のファンタジア/シルバーレイン/エンドブレイカー!/サイキックハーツへの携帯向けゲートウェイサービス「偽ログ」の管理者 アカウントです。 http://t.co/QMKlQjzjSI http://t.co/YEiNJUvGdU",
    "followers_count": 40,
    "id": 118604209,
    "id_str": "118604209",
    "listed_count": 5,
    "name": "niselog 管理者",
    "profile_background_color": "C0DEED",
    "profile_background_image_url": "http://abs.twimg.com/images/themes/theme1/bg.png",
    "profile_background_image_url_https": "https://abs.twimg.com/images/themes/theme1/bg.png",
    "profile_image_url": "http://abs.twimg.com/sticky/default_profile_images/default_profile_normal.png",
    "profile_image_url_https": "https://abs.twimg.com/sticky/default_profile_images/default_profile_normal.png",
    "profile_link_color": "1DA1F2",
    "profile_sidebar_border_color": "C0DEED",
    "profile_sidebar_fill_color": "DDEEF6",
    "profile_text_color": "333333",
    "profile_use_background_image": true,
    "screen_name": "niselog",
    "statuses_count": 340,
    "url": "http://t.co/QMKlQjzjSI",
    "withheld_in_countries": []
  },
  "user_mentions": []
}
-bash-4.2$

今度は可読できる状態になった。

で・・・twitter spaceの場合、次のような出力になっていた

{
  "created_at": "Fri Aug 13 02:11:56 +0000 2021",
  "hashtags": [],
  "id": ~,
  "id_str": "~",
  "lang": "ja",
  "source": "<a href=\"http://twitter.com/download/android\" rel=\"nofollow\">Twitter for Android</a>",
  "text": "スペース配信開始\nhttps://t.co/~",
  "urls": [
    {
      "expanded_url": "https://twitter.com/i/spaces/~",
      "url": "https://t.co/~"
    }
  ],
  "user": {
<略>
 }
}

urlsにexpanded_urlという項目があり、そこに /i/spaces/~ というtwitter spaceのURLが書かれているという状態であった。

とりあえず、これで、twitter spaceに参加するためのURLは取得できそう。

jqコマンドのオプションを変えて.urlsだけを抜き出して見る

-bash-4.2$ ./test3.py|jq '.urls'
[]
[]
[]
[]
[]
[]
[]
[]
[]
[]
[
  {
    "expanded_url": "https://twitter.com/i/spaces/~",
    "url": "https://t.co/~"
  }
]
[
  {
    "expanded_url": "https://~",
    "url": "https://t.co/~"
  }
]
[]
[]
[]
[]
[]
[]
[]
[]
-bash-4.

中身が入ってないものまで表示されてしまう。

jq コマンドを使う日常のご紹介」になかなかいい参考事例を発見

-bash-4.2$ ./test3.py|jq -r '.urls[] '
{
  "expanded_url": "https://twitter.com/i/spaces/~",
  "url": "https://t.co/~"
}
{
  "expanded_url": "https://~",
  "url": "https://t.co/~"
}
-bash-4.2$

これでURLがある場合だけ結果が出た。

もう1歩すすめてjqコマンドマニュアルみつつselectで完全一致だけ出力

-bash-4.2$ ./test3.py|jq -r '.urls[] |select(.expanded_url == "https://twitter.com/i/spaces/~")'
{
  "expanded_url": "https://twitter.com/i/spaces/~",
  "url": "https://t.co/~"
}
-bash-4.2$

部分一致を探すとstartswith,endswithで指定文字列で始まる場合/終わる場合を条件にできた

-bash-4.2$ ./test3.py|jq -r '.urls[] | select(.expanded_url | startswith("https://twitter.com/i/spaces/"))'
{
  "expanded_url": "https://twitter.com/i/spaces/~",
  "url": "https://t.co/~"
}
-bash-4.2$

含まれる場合は containsでいけた

-bash-4.2$ ./test3.py|jq -r '.urls[] | select(.expanded_url | contains("https://
twitter.com/i/spaces/"))'
{
  "expanded_url": "https://twitter.com/i/spaces/~",
  "url": "https://t.co/~"
}
-bash-4.2$

Cisco UCSのCIMCにssh接続して設定を行う


Cisco UCSのCisco Integrated Management Controller (CIMC)はWeb管理画面とssh接続によるCLI管理がある。

CIMCについているホスト名は基本的に「サーバ機種名-シリアル番号」となっている。

ホスト名を確認する操作をCLIから行うには、scope:cimc/network以下でdetailを表示する操作になる。

ホスト名# scope cimc/network
ホスト名 /cimc/network # show detail
Network Setting:
    IPv4 Enabled: yes
    IPv4 Address: xxx.xxx.xxx.xxx
    IPv4 Netmask: 255.255.255.0
    IPv4 Gateway: xxx.xxx.xxx.xxx
    DHCP Enabled: no
    DDNS Enabled: yes
    DDNS Update Domain:
    DDNS Refresh Interval(0-8736 Hr): 0
    Obtain DNS Server by DHCP: no
    Preferred DNS: xxx.xxx.xxx.xxx
    Alternate DNS: 0.0.0.0
    IPv6 Enabled: yes
    IPv6 Address: ::
    IPv6 Prefix: 64
    IPv6 Gateway: ::
    IPv6 Link Local: fe80::86b8:xxxx:xxxx:xxxx
    IPv6 SLAAC Address: ::
    IPV6 DHCP Enabled: yes
    IPV6 Obtain DNS Server by DHCP: yes
    IPV6 Preferred DNS: ::
    IPV6 Alternate DNS: ::
    VLAN Enabled: no
    VLAN ID: 1
    VLAN Priority: 0
    Port Profile:
    Hostname: ホスト名
    MAC Address: XX:XX:XX:XX:XX:XX
    NIC Mode: dedicated
    NIC Redundancy: none
    VIC Slot: riser1
    Auto Negotiate: yes
    Admin Network Speed: auto
    Admin Duplex: auto
    Operational Network Speed: 1Gbps
    Operational Duplex: full
ホスト名 /cimc/network #

show detailだといろんな項目が表示されすぎるので、ホスト名だけを取り出すことができないか調べたところ「| grep キーワード」が使えた。

ホスト名 /cimc/network # show detail | grep Hostname
    Hostname: ホスト名
ホスト名 /cimc/network #

ホスト名変更操作は scope:cimc/network にて set hostnameを実行したあと、commitで確定する。

ホスト名 /cimc/network # set hostname 新ホスト名
Create new certificate with CN as new hostname? [y|N] y

ホスト名 /cimc/network *# commit
Changes to the network settings will be applied immediately.
You may lose connectivity to the Cisco IMC and may have to log in again.
Do you wish to continue? [y/N] y

注意点として、ホスト名変更に伴い、Web管理GUIおよびssh接続で使用するSSL証明書で使用するCN(common name)が変更されるため証明書が作成されるということがある。

また、再作成に伴いCIMC自体も再起動されるため、commit後、再起動完了までの数分間CIMCに接続できなくなる。

このため、CIMCホスト名変更処理を行ったあとは、再起動待ちと証明書再発行にともなうssh接続時のキー変更に対応する処理を入れる必要がある。

ssh接続時のknown_hostsファイルから該当するエントリを削除したい場合は、 ssh-keygenコマンドの-Rオプションを使うことで行える。

osakanataro@ubuntu2004:~/imc$ ssh-keygen -R xxx.xxx.xxx.xxx
# Host xxx.xxx.xxx.xxx found: line 1
/home/osakanataro/.ssh/known_hosts updated.
Original contents retained as /home/osakanataro/.ssh/known_hosts.old
osakanataro@ubuntu2004:~/imc$

これで材料が揃ったので、スクリプトを作成する。

最初は Ciscoのcimc-ansible , cimcsdk を使用できないか検討したのですが、どちらもCIMCのホスト名変更に関する処理が実装されていないようだったので、expectコマンドによる処理を採用しました。

作成するにあたり下記を参考にしています。
How to programmatically enable redfish on Cisco CIMC?
Automate the UCS CLI with expect

今回作成したスクリプトは下記の様になりました。

#!/usr/bin/expect -f

# CIMCへの接続に時間がかかるようで
# 標準設定のtimeout値だとコマンド実行前にプロセスが進んでしまう 
# -1 を設定すると応答があるまで待つが
# ホスト名変更処理後は再起動がかかり、-1だと再起動が終わるまで待つことになってしまい時間がかかるので20に設定
set timeout 20

set CIMCaddr "xxx.xxx.xxx.xxx"
set CIMCuser "admin"
set CIMCpass "パスワード"
set CIMChostname "新ホスト名"


spawn ssh -l $CIMCuser -t $CIMCaddr
expect_after eof {exit 1}
# ログイン処理
expect {
        "*?assword:*" {
                send -- "$CIMCpass\r"
        }
        "(yes/no*)*" {
                send -- "yes\r"
                expect "*?assword:*"
                send -- "$CIMCpass\r"
        }
	# ホスト名変更時にssl証明書再作成が行われるため
	# キーが変わることに対する対応
	# リトライ処理が面倒だったので、古いキーを削除するところまでしか行わない
	# 必要に応じて手動で再実行で対応
        "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED" {
                system ssh-keygen -R $CIMCaddr
                puts "\nplease re-exec this script\n"
                exit 2
        }
}

expect "# "
send -- "scope cimc/network\r"
expect "# "

# 現在のホスト名確認
send -- "show detail | grep Hostname \r"
expect -indices -re "Hostname: (.*)\r"
# 文字列検出に使った": "の2文字分を足す
set strst [string last ": " $expect_out(buffer)]
set strst [expr $strst + 2]
# 行の終わりの改行分を引く
set stred [string length $expect_out(buffer)]
set stred [expr $stred - 2]
set hostnamenow [string range $expect_out(buffer) $strst $stred]
puts "CIMChostname: $CIMChostname"
puts "hostname: $hostnamenow"

# ホスト名の変更が必要か?
if { "$CIMChostname" != "$hostnamenow" } {
        puts "change hostname"
} else {
        puts "no change"
        expect "# "
        send -- "top\r"
        expect "# "
        send -- "exit\r"
        exit 0
}

# ホスト名変更
expect "# "
send -- "set hostname $CIMChostname\r"
expect "*new hostname?*"
send -- "y\r"
expect "# "
send -- "show detail | grep Hostname \r"
expect "# "
send -- "commit\r"
expect "*\[y/N] "
send -- "y\r"

# ホスト名確認
#  ただし実際には再起動が掛かっているので実行できない
expect "# "
send -- "show detail | grep Hostname \r"

expect "# "
send -- "top\r"
expect "# "
send -- "exit\r"

exit 0

expectでスクリプトを作った時のメモ書き


ssh経由の操作をexpectコマンドで自動化しようとした時に、expectで調べると、入出力関連に関しては出てくるが、文字列操作や制御構文周りがよくわからない。

ここら辺は、tclに関して調べるとわかるようになっている。

参考にしたサイト

LInux JM Home Page「expect (1)
FreeSoftNet 「Tcl>文法とコマンド
アプリコット PukiWiki「expectで自動化

if文の書き方

他の言語と同じように「if (条件){実行内容}」と書くと妙なエラーになる。

expectでは「if {条件} {実行内容}」というように、どちらも「{}」で囲む。
また、「if」と「{」の間、「条件の}」と「実行内容の{」の間のそれぞれにスペースを挟む必要がある。

文字列を比較して、異なる場合は「diff」、同じであれば「same」と出力するexpectは下記の様になる。

#!/usr/bin/expect -f
set hostnamenew "testhostnew"
set hostnamenow "testhost"

puts "hostnamenew: $hostnamenew"
puts "hostnamenow: $hostnamenow"

if { "$hostnamenew" != "$hostnamenow" } {
        puts "diff"
} else {
        puts "same"
}

誤って「if (条件) {実行内容}」とした場合、下記の様な「unbalanced open paren in expression」というエラーとなる。

unbalanced open paren
in expression "("
    (parsing expression "(")
    invoked from within
"if ( "$hostnamenew" != "$hostnamenow" ) {
        puts "diff"
} else {
        puts "same"
}"

「if(条件) {実行内容}」と「if{条件} {実行内容}」とifと{の間にスペースを入れない場合は下記のような「invalid command name」となる

invalid command name "if("
    while executing
"if( "$hostnamenew" != "$hostnamenow" ){"
invalid command name "if{"
    while executing
"if{ "$hostnamenew" != "$hostnamenow" }{"

面倒くさいことに「if {条件}{実行内容}」と、ifと条件の間にはスペース入れたけど、条件と実行内容の間にスペースがない場合は下記の「extra characters after close-brace while executing」というエラーになる。

extra characters after close-brace
    while executing
"if { "$hostnamenew" != "$hostnamenow" }{"

コマンド出力から文字列を取り出しと文字列の切り出し

expectを使う場合は、sshで他のホストに接続してコマンドを実行する、という用途で使うことが多い。

コマンドの実行結果によって、処理を変えたい場合、どうすればいいのか?

「expect -indices -re “条件式”」で条件式に該当した行を$expect_out(数字,string)で拾うみたいなんだけど、いまいち動作がよくわからない。

「ip a s ens160」を実行して、そのIPアドレスを取得したい場合の例として以下を作った

expect "\[#$] "
send -- "ip a s ens160\r"
expect -indices -re "inet (.*)\r"
puts "===buffer==="
puts "$expect_out(buffer)"
puts "===str0==="
puts "$expect_out(0,string)"
puts "===str1==="
puts "$expect_out(1,string)"
puts "===="

これの実行結果は下記となった。

2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:33:27:f8 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
===buffer===
ip a s ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:33:27:f8 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
===str0===
inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
===str1===
172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
====
       valid_lft forever preferred_lft forever
    inet6 fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever

条件を「inet (.*)\r」から「inet6 (.*)\r」に変更

2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:33:27:f8 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
===buffer===
ip a s ens160
2: ens160: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:33:27:f8 brd ff:ff:ff:ff:ff:ff
    altname enp3s0
    inet 172.17.44.48/16 brd 172.17.255.255 scope global noprefixroute ens160
       valid_lft forever preferred_lft forever
    inet6 fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
===str0===
inet6 fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
===str1===
fe80::cca7:388a:36e7:d688/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
====

ここからさらにIPアドレスの部分を取り出すには「string first ~」「string last ~」と「string range ~」を使って文字列を切り出す。

set str $expect_out(1,string)
set stred [string first "/" $str]
puts "[string range $str 0 $stred]"
set stred [expr $stred - 1]
puts "[string range $str 0 $stred]"

上記の実行結果としては下記のようになる。

172.17.44.48/
172.17.44.48

他の言語のsubstring系だと開始アドレスと、そこを起点に取り出す文字列の長さを指定するが、tclのstring range では、開始アドレスと終了アドレスの2つを指定する形になるので注意が必要になる。

リストファイルを順に処理する

サーバ名 IPアドレス ユーザ名 パスワードがかかれている一覧ファイルを読み込ませて順に処理させる例

まず、一覧ファイルの例

server1       172.17.44.51    admin   password123#
server2       172.17.44.52    admin   password123#

スクリプト

#!/usr/bin/expect -f

if { $argc < 1 } {
        puts "Usage: $argv0 <serverlist>"
        exit 1
}

set filename [lindex $argv 0]

set contents [read [open $filename]]
set contentline [split $contents "\n"]
foreach line $contentline {
        #puts "$line"
        set linesplit [split $line "\t"]
        set hostname [lindex $linesplit 0]
        set ipaddr [lindex $linesplit 1]
        set username [lindex $linesplit 2]
        set password [lindex $linesplit 3]
        if { $hostname != "" } {
                puts "hostname:$hostname, ipaddr:$ipaddr, username:$username, password:$password"
        }
}

実行例

$ ./sample3 serverlist
hostname:server1, ipaddr:172.17.44.51, username:admin, password:password123#
hostname:server2, ipaddr:172.17.44.52, username:admin, password:password123#
$

なお、処理スクリプトに「if { $hostname != “” } {」を入れているのは改行のみやEOFのみの行を処理してしまわないようにするため

とはいえ、これを応用してssh接続させるスクリプトにしたところ、間にアクセスできないホストがあると、そこでエラー終了してしまうので、取り扱いが面倒であることが判明。
(エラー時の処理を実装すればいいんだけど、面倒)

よって、bashスクリプト側でリストは処理し、そこからexpectスクリプトを呼び出すこととなった。