くんすとの備忘録

IT系技術メモ

移転しました。

15秒後に自動的にリダイレクトします。

コマンドプロンプトのワンライナーでズンドコキヨシ

cmd.exeでもやります。期待してましたよね?よね?

概要

最近流行の「ズンドコキヨシ問題」を、コマンドプロンプト(cmd.exe)のワンライナーで解いてみました。

cmd /v:on /c "for /L %i in (1,1,1000) do @call set /a a5=a4,a4=a3,a3=a2,a2=a1,a1=^%RANDOM^% % 2 >nul & set A=!a5!!a4!!a3!!a2!!a1!& if !a1!==1 (echo ズン) else (echo ドコ) & if !A!==11110 echo キ・ヨ・シ! & exit"

雑な解説

  • 処理を途中で終了する必要があるため、cmdコマンドでサブプロセスを起動する。
  • 0か1をランダムに1000回出力
    • ※この部分ね→for /L %i in (1,1,1000) do @call set /a a1=^%RANDOM^% % 2
  • 1のときは「ズン」0のときは「ドコ」を割り当て
    • 初期値が「0」になるので、逆にすると初回に「ドコ」が出たら終了しちゃう
  • 0か1だったという履歴(A)を5回まで保持(a1~a5)しておく。
  • 履歴(A)が「11110」のとき、つまり「ズン ズン ズン ズン ドコ」だった時、「キ・ヨ・シ!」を出力して子プロセスを終了する

【2015年度版】コマンドプロンプトのワンライナーでFizzBuzz

これは、コマンドプロンプト(cmd.exe) Advent Calendar 2015 - Qiitaの25日目、最終日の記事です。

Windows 10 Home 64bit 搭載のcmd.exeにて検証を行っています。


さて、これまでのFizzBuzz


ということで、2015年の脳みそでもう一度書いてみました。

for /L %i in (1 1 20) do @set /a a=%i%15,b=%i%5,c=%i%3>nul&if !a!==0 (echo FizzBuzz) else (if !b!==0 (echo Buzz) else (if !c!==0 (echo Fizz) else echo %i))

155バイト。2014年版とほとんど変わりませんね。
かなりシンプルで見やすいですし、わりと完成形かもしれません。

まとめ

コマンドプロンプト(cmd.exe) Advent Calendar 2015 - Qiita、見事に完走しました!
記事を書いてくださった、@k0hARCHさん、@ryoana14さん、@nmrmsysさん、ありがとうございました!!


それではみなさま良いお年を!!!!

うちのPCのプロビジョニング用BAT

これは、コマンドプロンプト(cmd.exe) Advent Calendar 2015 - Qiitaの23日目の記事です。

Windows 10 Home 64bit 搭載のcmd.exeにて検証を行っています。


さて、うちのメインマシンはLinuxでもMac OS XでもなくWindowsなんですが、数ヶ月に1回くらいのペースで再インストールしたくなるので、それに合わせて環境構築用のBATファイルを常用しています。

構成

ざっくり、以下のような構成です。
f:id:kunst1080:20151223173505p:plain

セットアップ

ファイルサーバ上で実行し、諸々をインストールする

  • Installer
  • Software-ZIP
同期

フォルダごと端末へコピーし、その上でジャンクションを張ったりする

  • profile
  • Roaming
  • usr
  • Git-repos
  • work

セットアップ

Installer

これは、chocolateyのためのパッケージ一覧と、インストーラのexe、そしてそれらを動かすプロビジョニング用BATで構成されています。

  • #pckage.config (chocolateyのためのパッケージ一覧)
<?xml version="1.0" encoding="utf-8"?>
<packages>
	<package id="lhaplus" />
	<package id="git" />

	<package id="google-chrome-x64 " />
	<package id="firefox" />
	<package id="flashplayerplugin" />
	<package id="skype" />
	<package id="line" />
	<package id="mpc-hc" />
	<package id="evernote" />

	<package id="atom" />
	<package id="imagemagick" />
	<package id="paint.net" />
	<package id="inkscape" />
	<package id="gimp" />
	<package id="audacity" />
</packages>
  • ###SETUP_by_ROOT.bat (プロビジョニング用BAT)
@echo off

pushd "%~dp0"

SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin


echo.
echo --- Chocolateyによるインストール ---
@where choco
if errorlevel 1 powershell -NoProfile -ExecutionPolicy unrestricted -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))"
cinst -y "#packages.config"



echo.
echo --- 自動・手動インストール  ---
for %%i in (
	"teraterm-4.86.exe /SILENT /LOADINF=teraterm.inf"
	SourceTreeSetup_1.6.14.exe
	TeamFileSet64-2.1.143.2013.exe
	GoogleJapaneseInputSetup.exe
	wlsetup-web.exe
	msys2-i686-20150916.exe
	LplsShlx64-v1.0.1.0\install.cmd
) do (
	echo "%%~i"
	start /w "%%~i" %%~i
)

pause

管理者でBATファイルを殴ると、Chocolateyによるインストールが実施され、その後同じフォルダ内にある指定されたインストーラが順番に起動します。インストーラはちょいちょい手作業が必要です。

手動の作業が混ざっていて悲しいですね。

Software-ZIP

これは、インストールしなくても使用できるソフトウェアのZIPファイルと、それらを解凍するプロビジョニング用BATで構成されています。
f:id:kunst1080:20151223171222p:plain

  • ####SETUP_by_USER.bat (プロビジョニング用BAT)
@echo off

pushd "%~dp0"

set DESTDIR=C:\Software
set LOGFILE=%DESTDIR%\log.txt

SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\tools

REM make directory
if not exist %DESTDIR% mkdir %DESTDIR%

for /f "usebackq tokens=*" %%i in (`dir /b *.zip`) do (
	if not exist "%DESTDIR%\%%~ni" (
		echo 7za x "%%~i" -o"%DESTDIR%\"
		7za x "%%~i" -o"%DESTDIR%\" >> "%LOGFILE%"
		echo.
	)
)
pause

一般ユーザでBATファイルを殴ると、C:\Software にディレクトリを作成し、同じフォルダ内にある全てのZIPファイルをそこに解凍してくれます。

こっちは全自動です。

同期

profile

ここには %USERPROFILE% 以下のフォルダが格納されており、プロビジョニング用BATでジャンクションを作成します。
f:id:kunst1080:20151223171458p:plain

  • #SETUP_by_USER.bat
@echo off

set ROOT=%~dp0.
set BKUPDIR=●init.%DATE:/=%

cd /d %USERPROFILE%

if not exist %BKUPDIR% mkdir %BKUPDIR%

@echo on
@for /f "usebackq tokens=*" %%a in (`dir /b /ad %ROOT%`) do (
	move %%a %BKUPDIR%\
	mklink /j %%a %ROOT%\%%a
)

pause

Roaming

ここには %USERPROFILE%\AppData\Roaming 以下のフォルダが格納されており、プロビジョニング用BATでジャンクションを作成します。
f:id:kunst1080:20151223171653p:plain

  • #SETUP_by_USER.bat
@echo off

set ROOT=%~dp0.
set BKUPDIR=●init.%DATE:/=%

cd /d %USERPROFILE%\AppData\Roaming

if not exist %BKUPDIR% mkdir %BKUPDIR%

@echo on
@for /f "usebackq tokens=*" %%a in (`dir /b /ad %ROOT%`) do (
	if exist "%%~a" move "%%~a" %BKUPDIR%\
	mklink /j "%%~a" "%ROOT%\%%a"
)

pause

usr

プロビジョニング用BATで、C:\usr からこのBATのあるフォルダへのジャンクションを作成します。
※ついでに環境変数の設定も行います

  • #SETUP_by_USER.bat

f:id:kunst1080:20151223171817p:plain

@echo off

set SRC=%~dp0
set DEST=C:\usr

if exist %DEST% (
    echo %DEST% はすでに存在します
    pause
    exit
)
@echo on
mklink /j %DEST% %SRC%

setx ROOT C:\usr
setx HOME %ROOT%\home
setx PATH "%PATH%;%ROOT%\lnk;%ROOT%\bin"

pause

work

プロビジョニング用BATで、C:\work からこのBATのあるフォルダへのジャンクションを作成します。

  • #SETUP_by_USER.bat
@echo off

set ROOT=%~dp0

cd /d C:\

if exist work (
    echo C:\work はすでに存在します
    pause
    exit
)
@echo on
mklink /j work %ROOT%
pause

Git-repos

ここには C:\Git-repos (Gitリポジトリ置き場) 以下にgit cloneしたいリポジトリのリストが置かれており、プロビジョニング用BATでgit cloneします。
f:id:kunst1080:20151223172154p:plain

  • list.txt
git@github.com:kunst1080/AnubisGG.git			kunst1080/AnubisGG
git@github.com:kunst1080/BatLibrary.git			kunst1080/BatLibrary
git@bitbucket.org:kunst1080/musics.git			kunst1080/musics
git@github.com:kunst1080/vm-install-freebsd.git		kunst1080/vm-install-freebsd
git@bitbucket.org:tsukiusagi_pj/lych.git		tsukiusagi_pj/lych
https://github.com/playframework/playframework.git	playframework/playframework
https://github.com/hakobera/nvmw.git			hakobera/nvmw
https://github.com/usp-engineers-community/Open-usp-Tukubai.git	usp-engineers-community/Open-usp-Tukubai

※git cloneするURLと、出力先(相対パス)をスペースで区切ったリストです

  • #SETUP_by_USER.bat
@echo off

set LIST=%~dp0list.txt
set DESTDIR=C:\Git-repos
set GIT="C:\Program Files (x86)\Git\bin\git.exe"

REM make directory
if not exist %DESTDIR% mkdir %DESTDIR%

REM Git clone
cd /d %DESTDIR%
for /f "usebackq tokens=1,2" %%a in (`type "%LIST%"`) do (
	echo git clone %%a %%b
	%GIT% clone %%a %%b
	echo.
)

pause

※スクショのある場所とない場所がありますが、お察しください。

D&Dされたファイルにタイムスタンプを付けてバックアップするBATファイル

これは、コマンドプロンプト(cmd.exe) Advent Calendar 2015 - Qiitaの22日目の記事です。

Windows 10 Home 64bit 搭載のcmd.exeにて検証を行っています。


ちょっとしたバックアップ取得用にBATファイルを使っています。

まずはソース

Archive_FLAT.bat
@echo off

REM 場所
set ARC_PATH=%CD%\●ARCHIVE
rem タイムスタンプ
set dt=%DATE:/=%
set tm=%TIME: =0%
set tm=%tm::=%
set tm=%tm:~0,6%
set TIMESTAMP=%dt%%tm%

rem 結局、ファイルを移動するのかコピーするのか?
set COMMAND=%~1
SHIFT



IF NOT EXIST "%ARC_PATH%" MKDIR "%ARC_PATH%"
IF "%~1"=="" (
	explorer "%ARC_PATH%"
	goto :eof
)

REM コピー処理
REM  ループする。
:COPY_LOOP
	rem ファイル名
	set FILE_NAME=%TIMESTAMP%_%~nx1%
	REM 確定フルパス
	set TARGET=%ARC_PATH%\%FILE_NAME%
	%COMMAND% "%~1" "%TARGET%"

	shift
if not "%~1"=="" goto :COPY_LOOP

goto :EOF

もしくは

Archive_DIR.bat
@echo off

REM 場所
set ARC_PATH=%CD%\●ARCHIVE\%DATE:/=%
rem タイムスタンプ
set dt=%DATE:/=%
set tm=%TIME: =0%
set tm=%tm::=%
set tm=%tm:~0,6%
set TIMESTAMP=%dt%%tm%

rem 結局、ファイルを移動するのかコピーするのか?
set COMMAND=%~1
SHIFT



IF NOT EXIST "%ARC_PATH%" MKDIR "%ARC_PATH%"
IF "%~1"=="" (
	explorer "%ARC_PATH%"
	goto :eof
)

REM コピー処理
REM  ループする。
:COPY_LOOP
	rem ファイル名
	set FILE_NAME=%TIMESTAMP%_%~nx1%
	REM 確定フルパス
	set TARGET=%ARC_PATH%\%FILE_NAME%
	%COMMAND% "%~1" "%TARGET%"

	shift
if not "%~1"=="" goto :COPY_LOOP

goto :EOF

ざっくりした機能

いずれも、D&Dされたファイルの先頭にタイムスタンプ文字列を付与して、バックアップフォルダ「●ARCHIVE」へ移動orコピーします。
「Archive_FLAT.bat」はそのまま、「Archive_DIR.bat」は今日の日付でサブディレクトリを作成しその中へバックアップされます。

使い方

どちらも、使いたい場所にショートカットを作成して使用します。
f:id:kunst1080:20151222102344p:plain

  • 「リンク先」の第一引数に、「MOVE」もしくは「COPY」を追記します。
    • 「MOVE」の場合は移動、「COPY」の場合はコピーされます。
  • 「作業フォルダー」に、バックアップフォルダを作成する場所を指定します。空白にすると、ショートカットの置いてある場所になります。


こんな感じで。

BATファイルでuniqコマンドを実装

これは、コマンドプロンプト(cmd.exe) Advent Calendar 2015 - Qiitaの21日目の記事です。

Windows 10 Home 64bit 搭載のcmd.exeにて検証を行っています。


BATファイルを使って簡易版uniqコマンドを作成します。

uniq.bat
@echo off
for /f "usebackq tokens=* delims=" %%i in (`findstr .*`) do call :sub %%i
goto :EOF 

:sub 
    if not "%PREV%"=="%*" (
        set PREV=%*
        echo %*
    )
exit /b

標準入力の1行1行をサブルーチンに渡し、サブルーチン内で「ひとつ前の行の値」を保持しているだけ、という単純な作りです。

使用例

入力ファイル (aaa.txt)

aaa

bbb


ccc
ccc
cccccc

bbb

実行

C:\usr\home>type aaa.txt | uniq
aaa
bbb
ccc
cccccc
bbb

C:\usr\home>type aaa.txt | sort | uniq
aaa
bbb
ccc
cccccc


いじょ。

BATファイルで、ロックファイルを使った排他制御を行う

これは、コマンドプロンプト(cmd.exe) Advent Calendar 2015 - Qiitaの20日目の記事です。

19日目は @nmrmsys さんの "Tee for ToeKick 実行コマンドラインまで含めてログファイルに出力するコマンド" でした。
残りは全部自分です。最後まで駆け抜けるよ!

Windows 10 Home 64bit 搭載のcmd.exeにて検証を行っています。

さてさて

今回はBATファイルにおける排他制御に関して書きますが、自分がやったことのある内容で、ということで、もうちょい範囲を限定します。
今回は「2つのBATファイルの実行について、ロックファイルを使った排他制御を行う」という内容で書きます。

挙動について

「処理1.BAT」と「処理2.BAT」の実行を排他制御します。

  • 「処理1.BAT」が起動した直後に「処理2.BAT」が起動すると「処理2.BAT」は待ち状態になり、「処理1.BAT」が終了すると「処理2.BAT」が動き出す
  • 「処理2.BAT」が起動した直後に「処理1.BAT」が起動すると「処理1.BAT」は待ち状態になり、「処理2.BAT」が終了すると「処理1.BAT」が動き出す
  • 「処理1.BAT」と「処理2.BAT」が同時に起動した場合、「処理1.BAT」が優先される

書きました

※検証しやすいように両方共最後にpauseを入れていますがお気になさらず

処理1.BAT
@echo off

set LOCK_PREFIX=lock
set LOCK_FILE=%LOCK_PREFIX%.proc1

rem チェック前にロックファイルを作成する
copy nul > %LOCK_FILE%

:CHECK
echo ロックファイルのチェック(%~n0)

rem 自分のロックファイルのみの場合、ERRORLEVEL=1
rem 他人のロックファイルが存在する場合、ERRORLEVEL=0
dir /b %LOCK_PREFIX%.* | findstr -v %LOCK_FILE% > nul
if %errorlevel%==0 timeout /t 2 > nul & goto :CHECK

:MAIN
echo 時間のかかる何らかの処理 開始
timeout /t 5 > nul
echo 時間のかかる何らかの処理 終了
echo.

:END
del %LOCK_FILE%

pause
処理2.BAT
@echo off

set LOCK_PREFIX=lock
set LOCK_FILE=%LOCK_PREFIX%.proc2

:CHECK
echo ロックファイルのチェック(%~n0)

rem 誰かのロックファイルが存在する場合、ERRORLEVEL=1
dir /b %LOCK_PREFIX%.* > nul 2>&1
if %errorlevel%==0 timeout /t 2 > nul & goto :CHECK

rem チェック後にロックファイルを作成する
copy nul > %LOCK_FILE%

:MAIN
echo 時間のかかる何らかの処理 開始
timeout /t 5 > nul
echo 時間のかかる何らかの処理 終了
echo.

:END
del %LOCK_FILE%

pause


簡単ですが、こんな感じで。

私見ですが、2つの処理の排他制御を完全に同じ形にするとかち合う可能性があるように思うので、上記でやったように、優先度をつけて微妙に異なる実装にする方が気が楽です。

Windows10のビルトインアプリの削除方法と戻し手順

いらないアプリ、いっぱいありますよね。消しましょう。

削除方法

不要アプリ削除.bat

※管理者権限で起動しましょう

@echo off

for %%i in (
3dbuilder
windowsalarms
windowscommunicationsapps
photos
windowscamera
soundrecorder
officehub
skypeapp
getstarted
windowsmaps
onenote
people
windowsphone
solitairecollection
zunemusic
zunevideo
xboxapp
bingfinance
bingsports
) do (
powershell -NoProfile -ExecutionPolicy Unrestricted -Command "Get-AppxPackage *%%i*" | findstr "^Name"
powershell -NoProfile -ExecutionPolicy Unrestricted -Command "Get-AppxPackage *%%i* | Remove-AppxPackage"
)
pause

戻し手順

全部戻す場合

powershellを管理者で開いて

Get-AppxPackage -AllUsers| Foreach {Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml"}

個別に戻す場合

OneNoteをインストールする

powershellを管理者で開いて

Get-AppxPackage -Name "Microsoft.Office.OneNote" -AllUsers | Foreach {Add-AppxPackage -DisableDevelopmentMode -Register "$($_.InstallLocation)\AppXManifest.xml"}