私は私のドットファイルの配布スクリプトを書いています。このファイルはデフォルトのGitリポジトリに保存されており、git checkout
何千ものGitチェックアウトエラーなしでスムーズに実行するために、そのリポジトリのファイルを自分のホームディレクトリに保存しています。すでに存在する項目(.bashrc
例:)を削除する必要がありますが、実際には次のように検索します。
git --git-dir=$HOME/repos/dots --work-tree=$HOME ls-tree --full-tree --full-name --name-only -r HEAD | sed "s|^|/mnt/home/henriquehbr/|"
注:その理由は、
/mnt
これが私のchrootインストール用のマウントポイントであり、実際にはカスタムArch Linuxインストールイメージで実行されているためです。
しかし、実際にはこれらのファイルを削除することは成功しませんでした。問題は、名前にスペースが含まれているファイルにあります(Font\ Awesome\ Icons.otf
例:)。
上記のコマンドを次のコマンドシーケンスに渡して、削除する各ファイルを参照してみました。
<get_dotfiles> | sed "s|^|\"/mnt/home/henriquehbr/|" | sed "s/$/\"/"
rm
上記はうまくいきません。引用符は文字通りファイル名の一部であるかのように扱われるようです。
もう一つの試みは良いループを作ることですfor
。
dotfiles=$(git --git-dir=$HOME/repos/dots --work-tree=$HOME ls-tree --full-tree --full-name --name-only -r HEAD | sed "s|^|/mnt/home/henriquehbr/|")
for dotfile in $dotfiles; do
echo "$dotfile" # Works properly, displays dotfile path
rm "$dotfile" # Doesn't works, writes: '$'\n'' after the path and fails
done
答え1
ヌルバイトを区切り文字として使用します。
git ls-tree -z … | xargs -0 rm
ほとんどのシェルでは、ヌルバイトを変数に入れることができないため、$(git ls-tree -z …)
便利な操作は行われません。
引用符を渡す引用文を使用しようとすると機能しませんrm
。rm
ほとんどのプログラムと同様に、ファイル名のみが必要です。"
ファイル名に表示される他の文字と同様に、通常の文字です。引用符を挿入することはシェルで置換するのに役立ちません。引用符($foo
または$(mycommand …)
)を持たない変数置換またはコマンド置換は単に空白に分割されます(各単語はワイルドカードパターンとして扱われます)、このステップでは引用符は関係ありません。ファイル名自体に「エキゾチック」な文字(バックスラッシュ、タブ、二重引用符など)が含まれていない場合は、引用符を挿入してに渡すことが機能しますが、xargs
andを使用するよりもはるかに複雑です。-0
git ls-tree -z
xargs -0
ファイル名にgit ls-tree
引用符で囲まれた文字(改行を含む)が含まれていないと仮定すると、次のように動作します(引用符を中断せずに)。
set -f # disable wildcard expansion (globbing)
IFS='
' # set only newline as the word separator
for dotfile in $(git ls-tree …); do …
これは良い考えではありません。実行時に既存のファイルを強制的に削除しようとすると、git checkout
Gitは実行時にファイルを削除しますgit checkout -f …
。重要なコンテンツが含まれている場合は、既存のファイルをチェックインする方が安全です。
git checkout -b original-files
git --git-dir=… ls-tree -z | xargs -0 git add
git commit -m "Original files on $HOSTNAME"
git checkout origin/master