web-dev-qa-db-ja.com

Macのターミナルで「rm」コマンドが正常に機能するのにシェルスクリプトからは機能しないのはなぜですか?

名前にスペースが含まれているディレクトリがあります。この特定のディレクトリの内容を削除する必要があります。内容を削除する前に、ディレクトリ名のスペースを\でエスケープしています。 rmコマンドはターミナルからは正常に機能しますが、シェルスクリプトで使用すると機能しません。 そのようなファイルやディレクトリはありませんエラーが発生します。

例:次のディレクトリ構造がありますUsers/Neeraj/Documents/temp dir/dir with spaces/a.txtディレクトリ「dirwithspaces」内のすべてを削除する必要があります。私のシェルスクリプトのコードは次のようになります

#!/bin/sh
TEMP_DIR="$HOME/Documents/temp dir/dir with spaces"
TEMP_DIR=$(echo $TEMP_DIR | sed 's/ /\\ /g')
COMMAND="rm -r $TEMP_DIR/*"
echo "Command: $COMMAND"
rm -r "$TEMP_DIR"/*

このスクリプトを実行すると、そのようなファイルやディレクトリはありませんエラーが発生しますが、スクリプトをコピーしてターミナルから実行すると、同じコマンドが正常に機能します。

出力:

Command: rm -r /Users/Neeraj/Documents/temp\ dir/dir\ with\ spaces/*
rm: /Users/Neeraj/Documents/temp\ dir/dir\ with\ spaces/*: No such file or directory

これを行う正しい方法は何ですか?

:私はmacOSを使用しています

1
Neeraj Damle

@Olorinsの回答はこの質問に対する正解ですが、さらに情報を追加したいと思います理由機能しません:


次のいずれかを使用できます。

rm "dir with spaces"
rm dir\ with\ spaces
dir="dir with spaces"; rm "$dir"

しかし、これらは機能しません:

dir="dir\ with\ spaces";
rm "$dir" # the backslash will be taken literally inside quotes 
rm $dir # this should work, shouldn't it? Please read below.

後者のオプションは、最初は直感的ではありませんでした。ただし、bashは変数の内容を拡張し、引用符を追加します実行前

set -xを使用して、実際に実行される内容を確認できます。

( var="a\ b"; set -x; echo $var; )
+ echo 'a\' b
a\ b

出力は良好に見えますが、\が一重引用符で囲まれているため、スペースはエスケープされていません。

2
pLumo

両方の引用符を使用していますおよびバックスラッシュ-エスケープ。引用するだけでうまくいきます。

これで十分です:

_TEMP_DIR="$HOME/Documents/temp dir/dir with spaces"
COMMAND="rm -r $TEMP_DIR/*"
echo "Command: $COMMAND"
rm -r "$TEMP_DIR"/*
_

この場合、バックスラッシュと引用符の両方がシェルによって処理され、ディレクトリ名が分割されないようにする必要があります。両方を使用する場合、シェルは両方のスペースを保持しましたおよび引用符内のバックスラッシュ。したがって、rmは実際には_.../temp\ dir/dir\ with\ spaces/..._を取得するはずの引数で_.../temp dir/dir with spaces/..._を取得します)__代わりに。

印刷されたコマンドをコピーすると、シェルは追加の引用符なしで円記号を確認するため、円記号で保護されたスペースを保持し、円記号を削除します。したがって、rmは引数に_.../temp dir/dir with spaces/..._を取得します。

1
Olorin