ハイパーマッスルエンジニア

Vim、ShellScriptについてよく書く

fzfで末尾に?がついてしまう現象

以下のような現象。

f:id:rasukarusan:20180825134545p:plain

多段scpを試みたときに出会った現象。ProxyCommandによる多段scpができなかったので、しょうがなく愚直に2回scpをしようとした。 expectで踏み台サーバーsshして、ls。lsの結果をfzfで絞り込んでscpする以下のようなスクリプトを組んだ。

serverFiles=`expect -c "
    spawn ssh -t serverA \"ssh $targetServer\"
    expect \"$USER\"
    send \"ls -1\n\"
    expect \"]\"
    expect \"$USER\"
    send \"exit\n\"
    "`
# 先頭行から6行目まではexpectの実行コマンドなので削除し、lsの結果だけを表示する
targetFile=`echo "${serverFiles}"| sed -e '1,6d' | grep -v $USER | fzf`
# 対象サーバーからserverAにコピー
ssh serverA "scp -r $USER@$targetServer:$targetFile $LOCAL_PATH"
# ローカルにコピー
scp -r serverA:$targetFile $LOCAL_PATH
# serverAにコピーしたファイルを削除
ssh serverA "rm -r $targetFile"

実行結果

▶sh scpServer.sh
: No such file...

scpで「そんなファイルないよ」と怒られる。

末尾の「?」は改行コードのCRだった

結論から言うと

targetFile=`echo "${serverFiles}"| sed -e '1,6d' | grep -v $USER | fzf`

targetFile=`echo "${serverFiles}"| tr -d '\r' | sed -e '1,6d' | grep -v $USER | fzf`

のようにtr -d '\r'をすればうまくいった。 どうやらlsした結果にCRが紛れ込んでいたようだった。

CRにたどり着くまでの道のり

推測1:fzfで絞り込んだ結果の$targetFileが空になっている?

targetFile=`echo "${serverFiles}"| sed -e '1,6d' | grep -v $USER | fzf`
echo $targetFile

# 実行結果
~
▶sh scpServer.sh
hoge.txt

変数名にはちゃんと入っているようだ。

推測2:「?」を消してみる

tr -d "?"で削除を試みたが結果は変わらず。。。

推測3:文字コードがおかしい?

どうやら目には見えないが内部的になにか変化しているのだろうと推測し、まずは文字コードからあたってみることにした。 nkf --guessをしてみる。

targetFile=`echo "${serverFiles}"| sed -e '1,6d' | grep -v $USER | fzf`
echo  $targetFile | nkf --guess

# 実行結果
▶sh scpServer.sh
ASCII (CRLF)

ほうほうなるほど。試しに普通にechoで文字列をawk --guessしたときどうなるか見てみる

echo "hoge" | nkf --guess
ASCII (LF)

ここで理解した。CRが紛れ込んでいたんだなと。 ecpect -c内の\nがsendでやると\rに変換されるのかなあ。 なぜCRが紛れ込むのかはまだ調査中だが、とりあえず一件落着だった。