5

(sedを使用してソリューションで編集)

チルダとワイルドカードを含むファイル名とディレクトリのリストがあります。例えば:

~/docs/file.*    
~/my docs/*.txt
...

行を読み取り、コマンド(rsyncなど)に渡します。

while read ROW
do
   rsync $ROW /my/dest/
done < list.txt

問題は、ファイル名にスペースを含めることです。$ROWをこのように二重引用符で囲むと

rsync "$ROW" /my/dest/

もちろん、bashはワイルドカードやチルダから逃れることはできません。ただし、引用符を使用しない場合、スペースによって行が分割されます。

考えられる解決策の1つは、IFSを変更することです(注意:スクリプトは、私が報告したものよりも複雑です)。別の解決策(Patrick Echterbruchの修正に感謝)は、スペースを事前にエスケープすることです。ただし、次のコードは私には機能しません。

while read ROW
do
    export NEWROW=$(echo $ROW | sed -e 's/ /\\ /g') 
    echo "Value: $NEWROW"
    ls -1d $NEWROW
done < list.txt

引用符はlsに渡されないことに注意してください。ファイル"〜/ abc / test.txt"が存在しますが、次のようになります。

Value: ~/saver/a\ b\ c/*.txt
ls: impossibile accedere a ~/saver/a\: Nessun file o directory
ls: impossibile accedere a b\: Nessun file o directory
ls: impossibile accedere a c/*.txt: Nessun file o directory

NEWROWが文字列としてlsに渡されるように見えるため、ワイルドカードは展開されませんが、スペースはエスケープされますが、ファイル名を壊し続けます。

ヒントはありますか?ありがとう。

4

2 に答える 2

1

私が見る限り、投稿した sed スクリプトは何の効果もありません。「検索」と「置換」の部分は同じです。

あなたができること:

ROW=$(echo $ROW | sed -e "s/ /\\\\ /g")

または(より良い):

ROW=$(echo $ROW | sed -e 's/ /\\ /g')

後者の例では、シェルがバックスラッシュを特別に扱わないように、一重引用符を使用しています。

発生した 2 番目の問題について: 特殊文字 ( など~) は、プログラムのパラメーターで検出されると、bash によって展開されます。それらを変数に格納するときは展開されません。また、変数をコマンドにパラメーターとして渡すときに、変数の内容を bash で検査して展開することもありません。

これがrsync $NEWROW ...機能しない理由です。rsync は $NEWROW の変更されていないコンテンツを最初のパラメーターとして受け取り、それ自体でシェルのような展開を行う必要があります。

私が知っている唯一の回避策は、コマンドをサブシェルで実行することです。

ROW="~/a b c"
$NEWROW=$(echo $ROW | sed -e 's/ /\\ /g')
bash -c "ls -ld $f"

これにより、現在実行中のbashが変数の内容を抽出します(つまり~/a\ b\ c、それを起動しようとしている2番目のシェルに渡します。この「内部」bashはパラメーターとともにコマンドを受け取り、もちろんパラメーター展開します。

最初にこの点を見逃して申し訳ありません。質問の正規表現部分のみに焦点を当てました。

別の可能な解決策を見つけました:sedを使用してパスを変換した後(たとえば、NEWROW=$(echo $ROW | sed -e 's/ /\\ /g')試してください:

eval ls -ld $NEWROW

または eval rsync $NEWROW /other/path

サブシェルの起動によるパフォーマンスへの影響なしに、これも同様に機能するはずです。

//編集: gsed スクリプトに欠落を追加

//編集: パス名展開の問題に対する回避策を追加

//編集: 評価ソリューションを追加

于 2011-01-18T10:27:19.173 に答える
0

次のように、リストをrsyncにパイプして別のファイルに入れ、実行できると思います

while read ROW
do
  echo "rsync '$ROW' /my/dest/"
done < list.txt > rsync.txt

sh rsync.txt
于 2011-01-18T10:37:35.133 に答える