置換や解釈なしで文字列リテラルを変数に保存するには?

置換や解釈なしで文字列リテラルを変数に保存するには?

ディレクトリ構造を平坦化するには、次のようにします。

find . -type f -exec sh -c 'mv "{}" "./`basename "{}"`"'  \;

私のプロフィールに以下を保存したいと思います:$ FLATTEN

-exec sh -c 'mv "{}" "./`basename "{}"`"'  \;

これにより、後で実行できます。find . $FLATTEN

早すぎると解釈され、変数を保存するのに問題があります。文字列リテラルとして保存してインポートするのではなく、シェルで使用した場合にのみ解釈したいと思います。

答え1

GNUを使用する場合は、mv次のようにする必要があります。

find . -type f -exec mv -t . {} +

他の人mv

find . -type f -exec sh -c 'exec mv "$@" .' sh {} +

{}コードを挿入しないでくださいsh。これは、ファイル名がシェルコード(`reboot`名前付きファイルを使用しようとするなど)として解釈されるため、コマンドインジェクションの脆弱性です。

quote コマンドの置換は良い点ですが、古代形式(`...`代わりに$(...))を使用しているので、内部二重引用符またはshBourne ShellまたはAT&T kshベースの実装では機能しません。(実際には矛盾"`basename "foo bar"`"(このシェルでは許可されている)と見なされ、接続されます)。"`basename "`foobar"`"

また、次のことを行うとき:

mv foo/bar bar

bar存在し、ディレクトリであれば実際にはディレクトリです。mv foo/bar bar/barそうmv -t . foo/barでなければ、mv foo/bar .そのような問題はありません。

これで、これらのパラメータ(、、、、、、、、)を変数に格納するには-exec配列変数が必要です。配列をサポートするシェルには、、、、、、、、などがあります。sh-cexec mv "$@" .sh{}+(t)cshkshbashzshrcesyashfish

ksh/bash/yashまたは以外の$FLATTEN変数を直接使用できるようにするには、合理的な配列実装を備えたシェルが必要です。また、ここではこれらのパラメータの中に空白がありません。"${FLATTEN[@]}"$FLATTEN:q(t)cshrcesfishzsh

存在するrc/ es/ zsh

FLATTEN=(-exec sh -c 'exec mv "$@" .' sh '{}' +)

存在するfish

set FLATTEN -exec sh -c 'exec mv "$@" .' sh '{}' +

その後、次のものを使用できます。

find . -type f $FLATTEN

答え2

これを達成して正しい結果を得るには、シェル関数を使用することをお勧めします(サブシェル-execに入れないでください)。{}

flatten () {
     ( cd "${1:-.}" && 
       find . -type f -exec sh -c 'for n; do test -e "${n##*/}" || mv "$n" "${n##*/}"; done' sh {} + )
}

また、外部ユーティリティを呼び出す必要はなく、basenameすでに存在するものを上書きしようとしません。

これを使用するために入力すると、flatten現在のディレクトリで動作します。ディレクトリ名を指定すると、そのディレクトリが実行されます(そのディレクトリの下のすべてのファイルをそのディレクトリの一番上にコピーします)。

答え3

関数はおそらく最良の方法でしょう。それ以外の場合は配列が必要ですeval

find_array=(-exec sh -c 'mv "{}" "./`basename "{}"`"'  \;)
find . "${find_array[@]}"

または

FLATTEN="-exec sh -c 'mv \"{}\" \"./`basename \"{}\"`\"'  \;"
eval find . $FLATTEN

答え4

機能はどうですか?

flatten(){
  find "$@" -type f -exec sh -c 'mv -- "$0" "${0##*/}"' {} \;
}

使用法:

> flatten .

使用すると選択zshできます。これにより、コマンド名だけでなく、グローバルに挿入されるエイリアスも定義できます。-galias

関連情報