LoginSignup
2
3

More than 5 years have passed since last update.

zsh で空白を含んだファイルの操作

Posted at

ファイル名に空白を含むファイル群に対して操作をする時のメモ.

IFS(Internal Field Separator)

ほとんどのシェル(少なくても zsh や bash)において,IFS(デリミター)のデフォルトは <スペース,タブ,改行, null文字>.

echo -n $IFS | od -ac
# 0000000   sp  ht  nl nul
#               \t  \n  \0
# 0000004

ls して得たファイル群を for で 回そうとすると,IFS の値によって出力が変化.

tree
#=>
# .
# ├── a\ 1.txt
# ├── a\ 2.txt
#
# 0 directories, 2 files

for file in `ls`; do
    echo $file
done
# default =>
# a
# 1.txt
# a
# 2.txt

# IFS=$'\n' =>
# a 1.txt
# a 2.txt

この原因は以下の実行結果からも確認可能.

ls | od -ac
# =>
# 0000000    a  sp   1   .   t   x   t  nl   a  sp   2   .   t   x   t  nl
#            a       1   .   t   x   t  \n   a       2   .   t   x   t  \n
# 0000020

IFS がコマンド実行に影響を与える例

以下は,IFS変更が他のコマンドに影響する例.

() { # 無名関数
  tree

  local IFS_ORG=$IFS
  local IFS=$IFS
  local array=()

  IFS=$'\n' # file は '\n' 区切りのブロック (->ファイル名) 
  for file in `ls`; do
    echo -e "\n${file}" :

    IFS=$IFS_ORG # 配列生成時のデリミター : ' \t\n\0' (->各要素ファイル名のスペース区切り)
    echo "IFS :"; echo -n ${IFS} | od -c
    array=(`echo $file`)
    for index in `seq ${#array[@]}`; do
      echo "array[${index}]: ${array[${index}]}"
    done; echo

    # 以下比較用コード 
    IFS=$'\n' # 配列生成時のデリミター : '\n'
    echo "IFS :"; echo -n ${IFS} | od -c
    array=(`echo $file`)
    for index in `seq ${#array[@]}`; do
      echo "array[${index}]: ${array[${index}]}"
    done; echo
 done
}

# =>
# .
# └── sec\ 1\ sub\ 1\ text.txt
# 
# 0 directories, 1 file
# 
# sec 1 sub 1 text.txt :
# IFS :
# 0000000       \t  \n  \0
# 0000004
# array[1]: sec
# array[2]: 1
# array[3]: sub
# array[4]: 1
# array[5]: text.txt
# 
# IFS :
# 0000000   \n
# 0000001
# array[1]: sec 1 sub 1 text.txt

空白を含んだファイルを扱うために IFS を変更すると他のコマンドの挙動にも影響し,思わぬ動作を引き起こすことも.
したがって,IFS を極力変更しない,または変更しても早い段階で元に戻したほうが安全.

余談

上記の例のように,zsh は配列のインデックスが 0 から始まるので注意.
以下のようにすればインデックスが 0 からスタート.

if [ "$ZSH_NAME" = "zsh" ]; then # zsh の時
  setopt localoptions ksharrays # ksh, bash ライクなインデックス(0からスタート)
fi

また,スクリプト内で setopt localoptions shwordsplit といったローカルなシェルオプションを設定すれば,"" で囲まずに変数展開した際にスペースで分割可能.
しかし,IFS を自分で変更したほうが柔軟かつ bash などとの互換性もあって良いかも.

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3