CD コマンドの機能拡張 第三版

CD コマンドの機能拡張 第二版」以来、16年ぶりの大幅修正。機能は変えていないが、リファクタリングで機能追加がシンプルになった。

cdd.batという名前で作って、doskey cd=cdd $*でaliasを定義して使う。

機能は、

  • 移動はすべて pushd で行う。
  • cd のみのときはディレクトリスタックの表示
  • ホーム(%HOME%)への移動は cd ~
  • cd - で前のディレクトリに戻る
  • cd + で現ディレクトリと一つ前のディレクトリの交換
  • cd 存在するディレクトリ だとそこへ移動
  • cd ショートカット の場合、ショートカット先がディレクトリならそこへ移動し、ファイルだとそのファイルのあるディレクトリへ移動
  • cd 存在するファイル だとそのファイルのあるディレクトリへ移動 (explorerからcmdプロンプトへファイルをドラッグ&ドロップしたとき便利)
  • cd それ以外 の場合環境変数CDPATHを探索してオペラランドがそこにディレクトリとして存在すればそこに移動

ほとんどの機能はモジュール化していて、ファイルの最後で定義する。 指定文字列 移動先ディレクトリ 指定文字列 サブルーチン

サブルーチンの1つとして、RubyのGemsディレクトリへの移動を書いてみた。 Firefoxのプロファイルディレクトリも、profiles.iniを読んで決めるようにしようかと思ったけど、面倒くさいわりにメリットが無いのでやめた。

@echo off
rem 定義済みの移動先ならそこに移動する
call :PreDefined "%~dpnx0" "%~1"
if not ERRORLEVEL 1 exit /b

rem 存在するディレクトリ、ファイル、ショートカットか?
rem ファイルの場合はそのディレクトリに移動する
if exist "%~1" (
  dir /b/ad "%~1" >NUL 2>NUL
  if not ERRORLEVEL 1 (
    call :Pushd "%~1"
  ) else (
    if /i "%~x1"==".lnk" (
      call :Shortcut "%~1"
      if not ERRORLEVEL 1 exit /b
    )
    call :Pushd "%~dp1"
  )
  exit /b
)

rem %CDPATH% に存在するディレクトリなら、そこに移動する
if not "%~$CDPATH:1"=="" dir /b/ad "%~$CDPATH:1" >NUL 2>NUL && (
  call :Pushd %~$CDPATH:1
  exit /b
)

:Pushd
rem 移動用処理
rem pushd が成功しても元と同じならpopdする(同じ履歴を残さないため)
for /f "delims=" %%X in ("%CD%") do (
  pushd %*
  if not ERRORLEVEL 1 for /f "delims=" %%Y in ('echo "%%CD%%"') do (
    if "%%X"=="%%~Y" popd
  )
)
exit /b

:Shortcut
rem ショートカットファイルのリンク先を調べてそこに移動する
setlocal enabledelayedexpansion
set "SV="
set "FILE="
for /f "delims=" %%A in ('more ^< "%~1"') do (
  set A=%%A
  if "!A:~1,2!"==":\" for %%B in (A B C D E F G H I J K L M N O P Q R S T U V W
     X Y Z) do if "!A:~0,1!"=="%%B" set "FILE=%%A"
  if defined SV (if defined FILE (set "FILE=!FILE!%%A")else set "FILE=!SV!\%%A")&set "SV="
  if "!A:~0,2!"=="\\" set "SV=%%A"
)
if defined FILE endlocal&call :Pushd "%FILE%"&exit /b 0
rem リンク先が見つからない場合
exit /b 1

:PreDefined
rem 定義済み移動先の処理を行う
rem 移動先ディレクトリ名 または 呼び出すサブルーチン名
setlocal enabledelayedexpansion
set "DATA="
for /f "usebackq tokens=1*" %%A in (%1) do (
  if /i "%%~A" == "__DATA__" (
    set DATA=1
  ) else if defined DATA (
    set "X=%%~B"
    if /i "%%~A" == "%~2" if "!X:~0,1!" == ":" (
      endlocal
      call %%~B %*
      exit /b 0
    ) else (
      endlocal
      call :Pushd "%%~B"
      exit /b 0
    )
    if /i "%~2" == ":Help" echo.%%A %%B
  )
)
if /i "%~2" == ":Help" exit /b 0
rem 定義済み移動先に存在しなかった
exit /b 1

rem ここから個別処理
:Dirs
rem ディレクトリスタックを横に並べて表示する
  setlocal enabledelayedexpansion
  set TEMPFILE="%TEMP:"=%\cd$$.tmp"
  pushd > %TEMPFILE%
  set "DIRS=%CD%"
  for /f "usebackq delims=" %%A in (%TEMPFILE%) do set "DIRS=!DIRS! %%~A"
  del %TEMPFILE% 2>NUL
  set /p "=%DIRS%"<NUL
  exit /b

:Back
rem 1つ前のディレクトリへ
  popd
  goto :Dirs

:Swap
rem 1つ前のディレクトリに移動して、履歴に今のディレクトリを入れる
  for /f "delims=" %%X in ('echo "%%CD%%"') do (
    popd
    for /f "delims=" %%Y in ('echo "%%CD%%"') do (
      popd
      for /f "delims=" %%Z in ('echo "%%CD%%"') do (
      if not "%%~Y"=="%%~Z" (pushd %%X) else (cd /d %%X) 
      if not "%%~X"=="%%~Y"  pushd %%Y
  )))
  goto :Dirs

:Help
rem 定義済み移動先の一覧の表示
  call :PreDefined %1 :Help
  exit /b

:RubyGems
rem RubyGemsのディレクトリへ
  for /f "tokens=1-3 delims=." %%A in ('ruby -e "puts RUBY_VERSION"') do (
    call :Pushd "D:\Ruby\lib\ruby\gems\%%A.%%B.0\gems"
  )
  exit /b

rem ここから移動先定義
__DATA__
""  :Dirs
-   :Back
+   :Swap
/?  :Help
~   %HOME%
/   %TEMP%
//  D:\Temp
/e  %windir%\system32\drivers\etc
/f  %APPDATA%\Mozilla\Firefox\Profiles\xxxxxxxx.20180101
/g  :RubyGems

スマートホームを少し始める

Amazon Echoと連携できる赤外線リモコン SwitchBot を買ってみました。

スマホアプリでコントロールすることもでき、Alexaアプリと連携することでEchoで指示できる。ただし、Echoで指示できるのは一部だけ。 寝室のPanasonicのシーリングライトとエアコンでやってみましたが、SwitchBotスマホアプリだとオンオフの他に明るさや温度調整ができるけど、Alexa/Echoだとオンとオフのみ。

シーリングライトは20年物のせいか、1回でで反応するときもあるけど、2回、3回と実行しないと反応しないこともあるので、Alexaアプリで3回実行する操作に名前を付けました。

Windows Updateでトラブル

WindowsUpdateで再起動したところ、Explorerからファイルを開こうとすると

指定されたデバイス、パス、またはファイルにアクセスできません。これらの項目にアクセスするための適切なアクセス許可がない可能性があります。

というエラーダイアログが出る。コマンドプロンプトからコマンドを明示して開くと開けるため、拡張子関連付けがおかしいと思われるので、レジストリを見てみる。

Dドライブに関して、D:\foo\barとなっているべきところが、軒並み*:\foo\barとドライブ名がアスタリスクに変わっている。 他にも拡張子関連付け自体が消えているものもある。

修正するともちろん問題ない。量が多すぎる(100以上)なので、exportしてプログラムで編集してregファイルを作ってimportした。手作業では無理。

いろいろアップデートするバッチスクリプト

MSYS、Ruby Gems、Python PIPsをアップデート。

pacman -Syu
call gem update --system
@echo on
call gem update
@echo on
for /f "skip=2" %%A in ('pip list -o') do python -m pip install -U --progress-bar off %%A

ThinkPad T480のクリックボタンのデグレ

5月に買ったThinkPad T480をようやく使い始めた。

Windows10のことはさておき、トラックポイントのクリックボタンの品質が劣化している。 人差し指で、トラックポイントを動かして、親指でボタンを押すわけだが、どうしてもボタンの端(センターボタンの脇)を押すことになる。 が、この反応が悪い。クリック音はするんだけど、反応しないことがしばしばあり、あれ?となってしまう。もう少し真ん中寄りを押せば大丈夫だが。

慣れるしかない。

f:id:otn:20190827204734j:plain

CMDのforのバグ

バグと言っていいのかどうか。ワイルドカード処理中にファイル名を変えると意図しない動作。

D:\Temp>dir /b
aaa.txt
bbb.txt
ccc.txt

D:\Temp>for %A in (*.txt) do ren %A ZZ%A
(実行結果)
D:\Temp>ren aaa.txt ZZaaa.txt
D:\Temp>ren bbb.txt ZZbbb.txt
D:\Temp>ren ccc.txt ZZccc.txt
D:\Temp>ren ZZaaa.txt ZZZZaaa.txt
D:\Temp>

3つのファイルなのにループを3回回った後、リネーム後のファイルをさらに処理する。

いろいろ試すと、「ワイルドカードが複数のファイルにマッチするときに、その(辞書順での)最後のファイル以外の1つ以上のファイルを、最後のファイルより辞書的に大きいファイル名にリネームして、かつ、最後のファイルもリネームした場合」のようです。

8年ぶりのPC買い換え

Windows7が来年1月でサポート切れとう事もあり、PCの買い換え。

調べると今のT520を買ったのが、2011年6月なのでほぼ8年使ったことになる。

連休限定の通常以上の割引率のクーポンがあったので、いろいろ考えた末購入。 15インチモデルはテンキーが付いてしまうので、サイズを落として14インチモデル。 今年モデルのT490を買うつもりだったけど、構成をいろいろ考えた結果、 SSD+HDDがえらべるのと、値引率も違うので、去年モデルのT480で。 55%引きともなると、標準価格って何だよと。

リミットまでまだ半年以上あるので、今後も通常以上のクーポンが出てくるとは思ったけど、その時にT480が買えるとは限らず、ここで思い切った。

ハードウェアだけじゃなくてOfficeもこの値引きなので、Office2019も購入。 Home&Businessが1万2千円くらいで買えることになる。

ThikPad T480

  • Core i7-8550U
  • Windows10/Pro
  • 32GBメモリ
  • 128GB SSD PCIe-NVMe
  • 1TB HDD 5400rpm
  • NVIDIA GeForce MX150
  • 1920x1080 IPS液晶 タッチパネル無し

ストレージは、1TB SSDだと、+4万円。高いけど思い切るべきだったかも知れない。まあ、メモリ32GBあるので。

Windows10の顔認証機能でログインできるらしいということで、赤外線付きカメラ。

タッチパネル液晶は+2000円くらいなので迷ったけど、わざわざキーボードから腕を持ち上げて使わないと思うのと、タッチ用のシートがある分で見えにくくなったら本末転倒と思い、止めた。 トラックポイントじゃなくてマウスを使う人なら良いのかも。