Rubyスクリプトのシェルスクリプトにファイル名を導入する方法

概要

シェルスクリプトを実行し、スペースを含むファイル名を渡したいRubyスクリプト。十数の方法を試してみました。ここにその 1 つがあります:

filename = "/Users/gscar/Pictures/_Photo Processing Folders/Watched folder for import to Photos/2024.03.25-16.09.59.gs.O.orf"
filename = filename.gsub(' ', '\ ')
'exiftool -Camera:DriveMode #{filename}'

その他にはパスのハードコーディングが含まれます

result = %x{exiftool -Camera:DriveMode /Users/gscar/Pictures/_Photo\ Processing\ Folders/Watched\ folder\ for\ import\ to\ Photos/2024.03.25-16.09.59.gs.O.orf}

その結果、

そして

system 'exiftool -Camera:DriveMode "/Users/gscar/Pictures/_Photo Processing Folders/Watched folder for import to Photos/2024.03.25-16.09.59.gs.O.orf"'

出力なし。

コマンドライン

➜ exiftool -Camera:DriveMode "/Users/gscar/Pictures/_Photo Processing Folders/Watched folder for import to Photos/2024.03.25-16.09.59.gs.O.orf"
Drive Mode                      : Single Shot; Electronic shutter

エスケープされたスペースを含むコマンドラインは機能します

➜ exiftool -Camera:DriveMode /Users/gscar/Pictures/_Photo\ Processing\ Folders/Watched\ folder\ for\ import\ to\ Photos/2024.03.25-16.09.59.gs.O.orf
Drive Mode                      : Single Shot; Electronic shutter

最終的に必要なのは、これが機能することです。上記は、ファイル名を機能させる方法を見つけようとしています。

filename = "/Users/gscar/Pictures/_Photo Processing Folders/Watched folder for import to Photos/2024.03.25-16.09.59.gs.O.orf"
gsubfilename = filename.gsub(' ', '\ ')
`"exiftool -Camera:DriveMode #{gsubfilename}"`

結果は次のようになります。

sh: exiftool -Camera:DriveMode /Users/gscar/Pictures/_Photo\ Processing\ Folders/Watched\ folder\ for\ import\ to\ Photos/2024.03.25-16.09.59.gs.O.orf: No such file or directory

もちろん、これをシェルで実行すると問題なく動作します。

ここで私を「逃がす」とは何ですか?ありがとう

PS mini_exiftool は「DriveMode」を処理していないようです。

解決策

コメントが示唆しているように、最善の方法はシェルを回避し、配列内の引数を使用してコマンドを呼び出すことです。具体的には、システムの場合、プログラム名以外に少なくとも 1 つの引数を関数に与えると、シェルは呼び出されません。

system('exiftool', '-Camera:DriveMode', filename)

このようにして、Ruby は exiftool を直接呼び出し、指定された引数を exiftool に渡します。シェルが関与していないため、パラメーターを展開することはできません (たとえば、system(‘ls’, ’’) は という名前のファイルが存在しないとエラーを出します)。

本当に引数の解析をシェルに委任したい場合は、シェル引数を正しくエスケープする方法を知っている Shellwords を使用してください。

require 'Shellwords'

system("exiftool -Camera:DriveMode #{filename.shellescape}")

この方法で呼び出すと、システムは /bin/zsh (例: /bin/sh) を呼び出し、渡された文字列を実行するように要求します。その後、シェルは通常と同じように文字列を処理し、文字列をコマンドと引数に分割し、パラメータの置換を実行し、コマンドを実行する前にシェルが行うその他すべての処理を実行します。したがって、system(’ls ’) は期待どおりの動作を行います。つまり、現在のディレクトリ内のファイルをリストします (シェルは ls を呼び出す前に を複数の引数に展開しているため)。