私は次のことをやろうとしています。
find . -name "*.dat" | get the basename of file | move filename returned by first command to basename returned by second command
./mydir1/dir2/file1.dat
具体的な例を挙げると、名前をに変更したいと思いますfile1.dat
。
パイプでできますか?それでは、最初のコマンドの出力を最初のパイプの変数に格納し、2番目のパイプでどのように使用できますか? 「パイプライン」という用語を正しく使用してほしいです。
答え1
find コマンドはこの作業を独自に実行するため、パイプは不要です。
find . -name "*.dat" -exec mv -t . {} \;
.dat
現在のディレクトリにすでに存在するファイルも検索して移動するため、これはやや非効率的です。
答え2
パイプラインの「水平」環境には実際に影響を与えることはできません。... p_n | p_n+1 | p_n+2 ...
パイプラインのプロセスは同じシェルソルバーによって生成されるため、環境変数を変更することはできません。たとえば、p_n
echiip_m
は同じパイプラインにあります。
ファイル名の単純な変換(正規表現を使用して実行できます)が必要な場合は、次のようにします。パールの例rename
すべきこと。以下を使用してxargs
エスケープの問題を回避したい場合、または必要な場合があります。
find ... -print0 | xargs -0 rename "regexps"
NULバイトを使用してファイル名を区別します(NULとバックスラッシュは通常ファイル名に表示されない唯一の文字です)。
ファイル名が正しく機能している場合(したがって、正規表現で使用される引用符、スペース、区切り文字などの特別な「奇妙な」文字エスケープが必要ないと仮定することができます)、次のようなすばやく汚れた操作を実行することもできます。
find ... | sed -r "regexps" | sh -
この場合、正規表現は有効なコマンド呼び出しmv
(または必要な操作を実行する他のコマンド)を生成する必要があります。これは次のとおりです。
"s|^.*$|mv -vi & &.old|"
これは次のようなものを生成します
...
mv -vi /etc/a2ps.cfg /etc/a2ps.cfg.old
mv -vi /etc/aclocal_dirlist /etc/aclocal_dirlist.old
...
単純な正規表現が十分に強力でない場合そうでなければ、あまりにも多くの問題になります、ファイル名を処理し、独自に名前を変更または移動する簡単なスクリプトを作成し、find(-exec
または)または.findを介して直接-exec +
呼び出しますxargs
。
最後に、複数のファイルのコピーを別のディレクトリに移動するには、および-t
オプションを使用します。 GNU coreutilsには、ソースとフルパスをコピーするオプションもあります。cp
mv
cp
--parents
答え3
可能な限り強力な方法で実際の問題を解決するには:
警告:コマンドラインが非常に長いです。
find "${directory:-.}" -type f -name "*.dat" -exec sh -c 'for dat; do
if [[ -e $dat ]]; then
base_fn=${dat%.*}$((++n)).dat
base_fn=${dat##*/}
else
base_fn=${dat##*/}
fi
mv "$dat" "$base_fn"
done' _ {} +
これは移植可能です。POSIXこれは実際に-exec ... {} +
最も一般的な用途を置き換えるように指定されていますxargs
。私の考えでは、GNUに特化したものがmv -t
良いと思います。唯一の注意点は、GNUがない場合は、各ファイルに対して新しいプロセスを作成するmv -t
必要があることです。mv
一方、ディレクトリ構造を平坦化すると、同じ基本名を持つファイルが破損する可能性があります。私のアプローチは、最も極端な場合を除いてこれを回避します(ARG_MAXが保存できるよりも多くのファイルがある場合、そして2番目の呼び出しでは、次のsh
場所にある別の重複したデフォルト名が見つかります。最初電話すると最初の電話が失われます。 )ああそうですね。これはコーディングが難しい極端なケースです。