我輩はブロガーではない。ネタもまだない

SASとかDelphiあたりの人様の役に立たないネタを提供します

x statementの処理がおかしい件

x statement、通称xコマンドではWindowsのcmdにコマンドを指定して実行することができます。

例えばこんな感じ。

x 'cd c:\temp';/* カレントディレクトリをc:\tempに変更 */
x 'copy c:\users\xxx\documents\test.xlsx c:\temp\text.xlsx';/* excelファイルをコピー */
x 'c:\temp\text.xlsx';/* excelファイルを開く */

そして、パスに空白を含む場合は、ダブルクオーテーションで括る必要がある、というのは周知の事実かと思います。
上の2つ目の例で言えば(パスに空白が含まれているなら)以下のようにしなければなりません。

/* 結果は全部同じ。ダブルクオーテーション「"」を2つ並べると、「"」として処理される */
x 'copy  "c:\users\xxx\documents\test.xlsx"   "c:\temp\text.xlsx"';
x 'copy ""c:\users\xxx\documents\test.xlsx"" ""c:\temp\text.xlsx""';
x "copy ""c:\users\xxx\documents\test.xlsx"" ""c:\temp\text.xlsx""";


ただ、マクロ変数を使って

%let cmd="path1 & path2 & path3 & ...";
X "&cmd";

のようなことをやりたかったので上記の3つ目のように

-" ""path1"" & ""path2"" & ""path3"" & ..."

という文字列を作成していたのですが、xコマンドが正しく実行できたりできなかったり。
(ここは&をエスケープしてません、念の為)

で、検証のために作成したのが以下のコードです。

options noxwait noxsync;
/* 検証用ファイル */
x 'cd c:\temp';
filename a 'a.txt';
filename b 'b.txt';
filename c 'c.txt';
data _null_;
  file a;
  file b;
  file c;
run;
filename a;
filename b;
filename c;

/*  1:OK */ x 'c.txt & ""a.txt""  & ""b.txt""';
/*  2:OK */ x 'c.txt &  "a.txt"   &  "b.txt"';
/*  3:OK */ x "c.txt & ""a.txt""  & ""b.txt""";
/*  4:NG */ x '        ""a.txt""  & ""b.txt""';
/*  5:NG */ x '         "a.txt"   &  "b.txt"';
/*  6:NG */ x "        ""a.txt""  & ""b.txt""";
/*  7:NG */ x         """a.txt""  & ""b.txt""";
/*  8:OK */ x '        ""a.txt""';
/*  9:OK */ x '         "a.txt"';
/* 10:OK */ x "        ""a.txt""";
/* 11:OK */ x         """a.txt""";

上記をsasの拡張エディタに貼り付けて1行ずつ実行すると、テキストファイルが開くもの(OK)と開かないもの(NG)があります。

4,5,6はそれぞれ1,2,3から先頭の「c:\temp\c.txt & 」を抜いただけで動作しなくなります。
8,9,10はそれぞれ4,5,6から末尾の「 & ""c:\temp\b.txt""」を抜いただけで動作するようになります。

xコマンドで最初にダブルクオーテーションでくくったパスと&を渡すと、きちんと処理できないような…。

ちなみに、xコマンドとクオートを外した以下のコードは全てコマンドプロンプトできちんと動くんです。

c:\temp\c.txt & ""c:\temp\a.txt"" & ""c:\temp\b.txt""
c:\temp\c.txt &  "c:\temp\a.txt"  &  "c:\temp\b.txt"
                ""c:\temp\a.txt"" & ""c:\temp\b.txt""
                 "c:\temp\a.txt"  &  "c:\temp\b.txt"
                ""c:\temp\a.txt""
                 "c:\temp\a.txt"

なんででしょう?