私はbashにかなり慣れていません。簡単なコマンドを1つずつ使用して、簡単な管理タスクを実行できます。ただし、名前の変更のソースとしてテキストファイルを使用して、ディレクトリ内のいくつかのファイルの名前を変更する必要があります。深みがないので、いくつかのポインタをいただければ幸いです。
説明させてください:
New File Name.xlsx 0.1 000011F4.dat
New File Name.xlsx 0.2 000011F5.dat
New File Name.xlsx 0.3 000011F6.dat
New File Name.xlsx 0.4 000011F7.dat
New File Name.xlsx 0.5 000011F8.dat
New File Name.xlsx 0.6 000011F9.dat
私が持っているソーステキストファイルは、上記にいくぶん似ています。最初の「列」はファイルの新しい名前、中央はバージョン、3番目は現在のファイル名です。
ディレクトリ内の.datファイルの名前を変更して、最初の列に表示されている名前に変更する必要があります。また、各ファイルの先頭にバージョン番号0.1、0.2などを追加する必要があります。
いくつかの質問を聞きたいんです:
ファイルに空白が含まれていることは大きな問題ですか?各ファイル文字列の周りに「」を追加したほうがよいでしょうか。
基本的にどこから始めればいいのかわからないので、助けていただければ幸いです。ご覧のとおり、通常の名前変更よりも少し複雑で、ファイル名の先頭とリストの空白にバージョン列を追加する必要があります。
これはうまくいくはずです:
sh <(sed -r 's/^\s*(.*)\s+([0-9\.]+)\s+([0-9A-Z]{8}\.dat)\s*$/mv -iv \3 "\2 \1"/' files)
...ここで、files
はソースファイルの名前です。
これは、 プロセス置換 を使用して、sed
コマンドの結果をsh
(シェル)の新しいインスタンスに渡します。 sed
コマンドの出力は次のとおりです。
mv -iv 000011F4.dat "0.1 New File Name.xlsx"
mv -iv 000011F5.dat "0.2 New File Name.xlsx"
mv -iv 000011F6.dat "0.3 New File Name.xlsx"
mv -iv 000011F7.dat "0.4 New File Name.xlsx"
mv -iv 000011F8.dat "0.5 New File Name.xlsx"
mv -iv 000011F9.dat "0.6 New File Name.xlsx"
sed
コマンドを分解して、パターンを検索します。
^
-行の先頭\s*
-先頭の空白(.*)
-任意の文字(括弧は結果を\1
に格納します)\s+
-少なくとも1つの空白文字([0-9\.]+)
-0-9
と.
の少なくとも1つ(\2
に保存)\s+
-少なくとも1つの空白文字([0-9A-Z]{8}\.dat)
-0-9
またはA-Z
の8文字、その後に.dat
(\3
に格納)\s*
-末尾の空白$
-行の終わり...そしてそれをmv -iv \3 "\2 \1"
に置き換えます。ここで、\1
から\3
は以前に保存された値です。必要に応じて、バージョン番号とファイル名の残りの部分の間にスペース以外のものを使用できます。
結果は次のとおりです。
$ ls -l
total 60
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F4.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F5.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F6.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F7.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F8.dat
-rw-rw-r-- 1 z z 0 Aug 8 14:15 000011F9.dat
-rw-rw-r-- 1 z z 222 Aug 8 13:47 files
$ sh <(sed -r 's/^\s*(.*)\s+([0-9\.]+)\s+([0-9A-Z]{8}\.dat)\s*$/mv -iv \3 "\2 \1"/' files)
`000011F4.dat' -> `0.1 New File Name.xlsx'
`000011F5.dat' -> `0.2 New File Name.xlsx'
`000011F6.dat' -> `0.3 New File Name.xlsx'
`000011F7.dat' -> `0.4 New File Name.xlsx'
`000011F8.dat' -> `0.5 New File Name.xlsx'
`000011F9.dat' -> `0.6 New File Name.xlsx'
$ ls -l
total 60
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.1 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.2 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.3 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.4 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.5 New File Name.xlsx
-rw-rw-r-- 1 z z 0 Aug 8 14:15 0.6 New File Name.xlsx
-rw-rw-r-- 1 z z 222 Aug 8 13:47 files
sed 's/^\(.*\.xlsx\) \+\([[:digit:]]\+\.[[:digit:]]\+\) \+\(.[^ ]*\)/"\3" "\2\1"/' \
<file_list | xargs -n 2 mv
これにより、行が.xlsx
の前の部分に分割されます。これは、新しい名前の2番目の部分であり、\1
としてアクセスできるようになります。バージョンを取得して\2
に割り当てます。次に、末尾のスペースを無視して、古いファイル名が表示されます。
これは、引数としてmv
に提供されたものとして引用されています。 -n 2
は、mv
が古いファイル名と新しいファイル名の2つの引数を受け取ることを保証します。
スペースは問題を引き起こしません。問題を複雑にするのは、入力リストが適切に構造化されていないことです。列が交換され、ファイル名が引用される場合は、事前の操作なしでxargs
とmv
を使用できます。
ファイル名のスペース、およびいくつかの列の間に複数のスペースを使用すると、これが難しくなりますが、決して克服できないわけではありません。
リストファイルを1行ずつ読み取ります。通常は while IFS= read -r; do …
を使用しますが、ここでは先頭と末尾の空白を削除する方が堅牢な場合があります。各行について:
[[:space:]]+
は1つ以上の空白文字(スペースまたはタブ)に一致します。 [[:space:]]+
は、1つ以上の非空白文字に一致します。括弧で囲まれたグループは、BASH_REMATCH
変数を介して取得できます。${VAR##PATTERN}
と${VAR%PATTERN}
を使用して、変数からプレフィックスまたはサフィックスをそれぞれ削除することです。すべてを一緒に入れて:
ret=0
while read line; do
if [[ $line =~ (.*[^[:space:]])[[:space:]]+([^[:space:]]+)[[:space:]]+([^[:space:]]+) ]]; then
new_name="${BASH_REMATCH[1]}"
version="${BASH_REMATCH[2]}"
old_name="${BASH_REMATCH[3]}"
mv -- "$old_name" "$version$new_name" || ret=1
else
echo "Malformed line: $line"
fi
done <name_list.txt
exit $ret
awk
の解決策は、次のコマンドを実行することです。
awk '{print "/bin/mv", $NF, "\"" $(NF-1), gensub(/^([^.]+\.xlsx).*/, "\\1", 1) "\"" | "bash" } ; END { close("bash") }' sourcefile
上記のコマンドは、コマンドの出力をbash
シェルに渡します。
awk '{print "/bin/mv", $NF, "\"" $(NF-1), gensub(/^([^.]+\.xlsx).*/, "\\1", 1) "\""}' sourcefile
これを最初に実行して、本当に実行したいものであることを確認する必要があります。このawk
コマンドは、ソースファイルの各行に対して、/bin/mv
コマンド、行の最後の空白区切りフィールド、二重引用符、2番目のコマンドを出力します。行の最後のフィールドの後に、行全体を文字列.xlsx
のすべてに置き換えた結果が続き、その後に二重引用符が続きます。
これがあなたが好むかもしれない変種です:
awk '{print "/bin/mv", $NF, "\"" "0." FNR, gensub(/^([^.]+\.xlsx).*/, "\\1", 1) "\"" | "bash" } ; END { close("bash") }' sourcefile
変数FNR
は行番号です(したがって、ソースファイルからエントリ0.1、0.2、0.3、...を省略できます)。
ファイル名の空白は、私が「大規模な問題」と呼ぶものではありませんが、反対することをお勧めします。この最終バージョンのようなものを使用すると、新しいファイル名のスペースがアンダースコアに変更されます。
awk '{print "/bin/mv", $NF, "0." FNR "_" gensub(" ","_", "g", gensub(/^([^.]+\.xlsx).*/, "\\1", 1)) | "bash" } ; END { close("bash") }' sourcefile