Unixの名前変更コマンドパイプ

Unixの名前変更コマンドパイプ

コマンドがファイル名のみを印刷する方法はありますかrename(プレフィックスXXX renamed asまたは括弧を除く)?唯一のオプションでない場合は、正規表現を使用しないことをお勧めします。

尋ねる理由: ファイル名が見えないように、何度も連続してファイル名 (実際にはファイルのリスト) を変更したいと思います。最初の名前変更で名前が変更された場合は、2番目の名前変更コマンドに入力できるファイルの新しい名前を取得する簡単な方法がないため、これは困難です。

はい

%20これにより、Webからダウンロードしたファイルの名前がに変わります。同じパイプラインの後続のコマンドでは、名前をに変更したい場合があります。正規表現が複雑なため(可能であれば)、単一の名前変更コマンドを使用したくありません。%28(

find -iname "*%20*" | xargs -n 1 rename --some-option 's/%20/ /g' |  xargs -n 1 rename --some-option 's/%28/(/g'

答え1

一連のsedコマンドを使用して、開始ファイル名を最終ファイル名に変換してから実行します。一つ mv実際の名前変更ファイル:

for i in *%*
do
    printf "mv -v '%s' '%s'\n" "$i" \
      "$( sed -e 's/%20/ /g' \
              -e 's/%28/(/g' \
         <<< "$i" )"
done

このコマンドのリストは実際にファイルを変更せず、これは良いことです。mv実際に必要な操作を実行するために使用できるコマンドを出力するだけです。

%20以下を含むいくつかのサンプルファイルを作成しましょう%28

$ for i in foo bar farkle
> do
>     touch $i"%20".txt; touch $i"%28".txt; touch $i"%20-%28".txt
> done
$ ls -1
bar%20-%28.txt
bar%20.txt
bar%28.txt
farkle%20-%28.txt
farkle%20.txt
farkle%28.txt
foo%20-%28.txt
foo%20.txt
foo%28.txt

それでは、最初に提供されたコマンドのリストを実行してみましょう。

$ for i in *%*
> do
>     printf "mv -v '%s' '%s'\n" "$i" \
>       "$(sed -e 's/%20/ /g' -e 's/%28/(/g' <<< "$i")"
> done
mv -v 'bar%20-%28.txt' 'bar -(.txt'
mv -v 'bar%20.txt' 'bar .txt'
mv -v 'bar%28.txt' 'bar(.txt'
mv -v 'farkle%20-%28.txt' 'farkle -(.txt'
mv -v 'farkle%20.txt' 'farkle .txt'
mv -v 'farkle%28.txt' 'farkle(.txt'
mv -v 'foo%20-%28.txt' 'foo -(.txt'
mv -v 'foo%20.txt' 'foo .txt'
mv -v 'foo%28.txt' 'foo(.txt'

コマンドの順序mvが正しいと思われる場合は、上矢印を使用してコマンドを再実行してください。ただし、今回はコマンドを表示するのではなく、| sh実際にコマンドを実行するように最後に追加してください。mv

答え2

本質的に、これは解決された問題であるURLデコードの練習であるようです。

次の名前で保存してくださいrename_script.sh

DECODED="$(awk -niord '{printf RT?$0chr("0x"substr(RT,2)):$0}' RS=%.. <<< "${1}")"
[ ! -f "${1}" ] && echo "Source not found" && exit 1
[ -f "${DECODED}" ] && echo "Target already exists" && exit 1
[ "${1}" != "${DECODED}" ] && mv -i "${1}" "${DECODED}" || echo "Nothing to do"

次のように呼び出します。

find -name "*%*" -print0 | xargs -n1 -0 ./rename_script.sh

この回答を強くお勧めします。 https://stackoverflow.com/a/14000368/2858703

答え3

find . -type f -name '*%*' -execdir bash -c '
    name=$1
    name=${name//%20/ }    # replace each %20 by a space
    name=${name//%28/(}    # replace each %28 by a (
    mv "$1" "$name"' bash {} \;

findこれは、名前に文字が含まれている現在のディレクトリ内または下の一般的なファイルを見つけるために使用されます%。これらの各ファイルに対して、指定されたbashファイル名について述べた2つの置換を実行し、ファイル名を変更する短いスクリプトが実行されます。

追加のパラメータ置換を簡単に追加して、ファイル名の他の文字列を削除または変更できます。

潜在的に高速な方法は、同じタスクを実行する単純なループを作成することです(bashこの特定のバリエーションにシェルが使用されていると仮定)。

shopt -s nullglob dotglob globstar

for pathname in ./**/*%*; do
    # skip pathnames to non-regular (or links to non-regular) files
    [[ ! -f "$pathname" ]] && continue

    name=${pathname##*/}    # strip off directory components
    name=${name//%20/ }     # ... so that we don't accidentally
    name=${name//%28/(}     # ... modify the directory path

    # the destination is made up by the directory path
    # (original pathname with filename stripped off) 
    # followed by the new name
    mv "$pathname" "${pathname%/*}/$name"
done

シェルnullglobオプションを使用すると、パターンは./**/*%*次に拡張されます。何もない一致するものがない場合(通常は拡張なし)、dotglobワイルドカードパターンが隠された名前を処理できるようにし、サブディレクトリの「再帰的」一致をglobstar許可します**

findワイルドカードパターンの内容の代わりにパス名を生成するために使用される2番目のループを調整します(例:bash4以前のバージョンで実行されていない場合**)。

find . -type f -name '*%*' -exec bash -c '
    for pathname do
        name=${pathname##*/}    # strip off directory components
        name=${name//%20/ }     # ... so that we don't accidentally
        name=${name//%28/(}     # ... modify the directory path

        # the destination is made up by the directory path
        # (original pathname with filename stripped off) 
        # followed by the new name
        mv "$pathname" "${pathname%/*}/$name"
    done' bash {} +

関連情報