realpathまたはreadlinkによって返された絶対パスをサニタイズまたはエスケープするにはどうすればよいですか?


9

realpathreadlink絶対パスを返します:

+akiva@X230:~$ realpath ZannaIsAwesome
/home/akiva/ZannaIsAwesome

このようなパスは簡単に処理できます。ただし、このようなものにはいくつかの問題があります:

ここに画像の説明を入力してください

例えば:

ここに画像の説明を入力してください

したがって、このような名前は、他のコマンドにフィードできるようにするために、無害化する必要があります。ユースケースは次のようなものです。

+a@X230:~/\e[92mM@r|< $hu+'|'|_e|\|\|0rth [`-_-"]$ bacon=$(realpath pullingATerdon)
+a@X230:~$ vim $bacon 

言うまでもなくvim $bacon、期待どおりに動作しません。

他のコマンドで機能するように、絶対パスをサニタイズするにはどうすればよいですか?


3
常に変数を引用してください:vim "$bacon"
steeldriver '14 / 03/17

@steeldriverなぜですか?
Akiva 2017年

3
そうしないと、次のような状況になります:)
terdon

回答:


12

これを正しく行う方法

まず、常に変数を引用してください。あなたがそれを正しく引用すればあなたがやろうとしていることはうまくいきます:

$ pwd
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]
$ ls
pullingATerdon

一貫性を保つために、あなたが選択した奇妙なファイル名を保持しました(なぜそれを選択したのかはわかりません)。

次に、pullingATerdon変数のパスを割り当ててから、ファイルを開こうとします。

$ bacon="$(realpath pullingATerdon)"
$ echo "$bacon"
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]/pullingATerdon
$ ls $bacon
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':

予想通り、それは失敗します。しかし、正しく引用すると、次のようになります。

$ ls -l "$bacon"
-rw-r--r-- 1 terdon terdon 0 Mar 14 23:15 '/home/terdon/foo/\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]/pullingATerdon'

期待どおりに動作します。そして、はい、パスを(適切な)エディターで開くこともできますemacs "$bacon"。問題なく動作します。はい、そうvimです。エディターの選択は、残念ながら関係ありません。


なぜ失敗したのか

ケースで実際に何が起こったかをすばやく追跡する方法は、を使用することですset -x(これをでオフに戻すset +x)。これにより、シェルは、実行する各コマンドを実行前に出力します。シェルのデバッグメッセージをオンにしますset -x

$ set -x
$ /bin/ls $bacon 
+ ls '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':

これは、とのls3つの個別の引数で実行されたことを示しています。これは、シェルが引用符で囲まれていない文字列に対して単語分割とグロブ拡張を実行するために発生します。この場合、シェルはパス内のスペースを認識し、スペースで区切られた各文字列を個別の引数として読み取るため、問題は単語の分割です。'/home/terdon/foo/\e[92mM@r|<''+'\''|'\''|_e|\|\|0rth''[`-_-"]/pullingATerdon'

mkdirあなたは私たちからのエラーメッセージ表示しているので、例はわずかに異なっているが、その者の第二のコマンドの呼び出しを。一度試した後、もう一度実行して質問の出力を取得したと思います。初めて実行したときは、次のようになります。

$ mkdir $(realpath pullingATerdon)
++ realpath pullingATerdon
+ mkdir '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
mkdir: cannot create directory ‘[`-_-"]/pullingATerdon’: No such file or directory

繰り返しになりますが、単語分割のため、1つではなく3つのディレクトリを作成しようとします。まず、(正常に)ディレクトリを作成しました/home/terdon/foo/\e[92mM@r|<

$ ls -l /home/terdon/foo/
total 8
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|<'
drwxr-xr-x 3 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]'

次に、+'|'|_e|\|\|0rth現在のディレクトリに呼び出されるディレクトリも正常に作成されました。

$ ls -l
total 4
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:37 '+'\''|'\''|_e|\|\|0rth'
-rw-r--r-- 1 terdon terdon    0 Mar 15 00:36  pullingATerdon

そして、ディレクトリを作成しようとしました[`-_-"]/pullingATerdon。これはmkdir、デフォルトではサブディレクトリを作成しないため失敗しました(で実行すると、サブディレクトリが作成されます-p)。

$ mkdir baz/bar
mkdir: cannot create directory baz/bar’: No such file or directory

あなたの引用符で囲まれていない文字列が含まれているので/mkdir二つのディレクトリのパスは、トップのものを見つけることを試み、失敗したと考えました。

それが失敗した理由ですが、発生したことはより複雑です。あなたが使用する文字列は、実際にシェルグロブ、特にあるグロブ範囲名前が5つの文字の一つであり、現在のディレクトリ内のすべてのファイルと一致し、`-_または"。現在のディレクトリにそのようなファイルがないため、グロブは何にも一致せず、bashのデフォルトの動作と同様に、自身を返します。

$ echo "[\`-_-\"]/pullingATerdon"  ## some escaping is needed here
+ echo '[`-_-"]/pullingATerdon'    ## but it echoes the right thing
[`-_-"]/pullingATerdon             ## and matches nothing, so returns itself.

明確にするために、何かに一致するグロブを指定した場合、次のようになります。

$ echo [p]*   ## any filename starting with a p
pullingATerdon
$ echo "[p]*" ## the string "[p]*"
[p]*

引用符で囲ま[p*]れていないものは、一致するファイル名のリスト(この場合は1つだけ)に展開され、それがに渡されechoます。あなたがすべてのものを引用するべきもう一つの理由。

最後に、表示される実際のエラーは、コマンドを2回実行したときのものであり、最初のステップでcreateを試行すると失敗します/home/terdon/foo/\e[92mM@r|<。これは、前の呼び出しですでにそのディレクトリが作成されているためです。


より一般的には、任意のファイル名で作業している場合は、常にシェルグロブを使用してください。このようなもの:

for file in *; do command "$file"; done

これはどのファイル名でも機能します。何が含まれていても。上記の例では、次のようにすることができます。

emacs /home/terdon/*92mM*/pullingATerdon

ターゲットファイルを一意に識別するグロブはすべて機能します。そうすれば、特殊文字を気にする必要がなく、シェルにそれらを処理させるだけで済みます。


いくつかの参考資料:

  1. 改行、スペース、またはその両方を含むファイル名を見つけて安全に処理するにはどうすればよいですか?:優れたGrey CatのWikiに関するFAQの1つ。

  2. bash / POSIXシェルで変数を引用するのを忘れることのセキュリティへの影響:この回答の冒頭で参照したのと同じ投稿。シェル変数を正しく引用しなかった場合に失敗する可能性があるすべての事柄についての非常に詳細な説明。

  3. シェルスクリプトで空白やその他の特殊文字が詰まるのはなぜですか?:シェルでの任意のファイル名の処理について知りたいことすべて。

  4. 二重引用符はいつ必要ですか?:引用符と変数の詳細、特に引用符を付ける必要がないいくつかのケース

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.