複数のディレクトリがあり、繰り返し繰り返してファイル名を変更したいと思います。
*.GEOT14246.*
到着
*.GEOT15000.*
bashスクリプトにこれを行う行はありますか?それともforループを持つスクリプトを書く必要がありますか?私の試みは(動作しません)次のようになります。
#!/bin/bash
for file in `find . -type f -name "*.GEOT14246.*"`
do
echo "file = $file"
mv $file *.GEOT15000.*
done
それから電話します。
cd /path/to/script/
sh ./script1.sh /path/to/starting/dir
明らかに、これは開始ディレクトリパスをパラメータとして渡すとは思わないので、うまくいかないようです。私はUnixに初めてアクセスしていますが、どのディレクトリで検索を開始する必要があるかを知らせるためにパラメータを渡し、スクリプトが機能するようにするにはどうすればよいですか?
答え1
これは働きます:
find . -type f -name "*.GEOT14246.*" -print0 | \
xargs -0 rename 's/GEOT14246/GEOT15000/'
名前付きディレクトリがないと仮定すると*.GEOT14246.*
find を使用する bash バリアントは次のとおりです。
while IFS= read -r -d $'\0' file; do
printf "MV: %-40s => %s\n" "$file" "${file/GEOT14246/GEOT15000}"
mv "$file" "${file/GEOT14246/GEOT15000}"
done < <(find . -type f -name "*.GEOT14246.*" -print0)
| |
+--- this is starting directory +--- This ensures no hiccup
if newline etc. in name
相対的ですが、完全なパスはfindから渡されます。
printf
これはステートメントで確認する必要があります。
新しい名前は bash を使用してコンパイルされます。
${some_variable/find/replace}
find
すべての用途を変更します。
${some_variable//find/replace}
など。ここでもっと学ぶ。これはまた良い読書かもしれません:バッシュトラップ、検索の使用。
次のガイドをお読みください。バッシュガイド。オンラインでいくつかのチュートリアルを見つけましたが、一般的に信頼できません。ここまたはirc.freenode.net#bashでお問い合わせください。
スクリプトを呼び出す必要はありませんsh
。これはBourne Againシェル(bash)ではなく、Bourneシェル(sh)とも呼ばれます。 bashで実行する予定の場合は問題がありますbash file
。.sh
拡張子も不適切です。
一般的に行うことは、以下を介してファイルを実行可能にすることです。
chmod +x script_file
次に実行します。
./script_file
これシェルボーンスクリプトを実行する必要がある環境を担当します。
スクリプトは渡されたパス名をどこにも使用しません。スクリプトには、$0
スクリプト名、$1
最初のパラメータ、$2
2番目のパラメータなどで始まる「パラメータのリスト」があります。
スクリプトで次の操作を行います。
# Check if argument 1 is a directory, if not exit with error
if ! [[ -d "$1" ]]; then
printf "Usage: %s [PATH]\n" "$(basename "$0")" >&2
exit 1
fi
# OK
path="$1"
while ...
done < <(find "$path" -type f ...)
現在のmv
ステートメントは、コマンドが実行されているどこにいてもすべてのファイルを移動します。.GEOT14246.(すべてのmv
声明を扱うのと同じ):
スクリプトが実行される前:
$ tree
.
└── d1
├── a1
│ ├── a2
│ │ ├── a3
│ │ │ └── foo.GEOT14246.faa
│ │ └── foo.GEOT14246.faa
│ └── foo.GEOT14246.faa
└── b1
├── b2
│ ├── b3
│ │ └── foo.GEOT14246.faa
│ └── foo.GEOT14246.faa
└── foo.GEOT14246.faa
スクリプトが実行された後:
$ tree
.
├── d1
│ ├── a1
│ │ └── a2
│ │ └── a3
│ └── b1
│ └── b2
│ └── b3
└── *.GEOT15000.*
また、スペースやその他の奇妙な内容を含むファイル/パスがスクリプトを破損し、混乱を招く可能性があります。したがって、変数を引用する必要があります(例"$file"
:)。
答え2
Bash 4.0以降では、globstarを使用することもできます。
shopt -s globstar
for f in **/*GEOT14246*; do mv "$f" "$f{/14246/15000}"; done
rename s/14246/15000/ **/*GEOT14246*
- globパターンは、GEOT14246を含むフォルダとも一致します。
- どちらのオプションもフルパスに適用されます。
- glob パターン拡張長を超える場合
getconf ARG_MAX
または、検索と読み取りを使用します。
find . -name '*GEOT14246*' | while read f; do mv "$f" "${f/14246/15000}"; done
-print0
パスに改行文字が含まれていない場合は必要ありません。IFS=
IFS では、パスが文字で始まったり終わったりしない場合は必要ありません。-r
パスにバックスラッシュが含まれていない場合は必要ありません。< <()
変数またはwhileループの外側の項目を変更しない限り、以下は必要ありません。
答え3
Bashにはシンプルなシングルライナーはありませんが、zshにはあります。それautoload -U zmv
から~/.zshrc
。zmv
そしてzshワイルドカードそしてパラメータの置換。
zmv '/path/to/starting/dir/**/*GEOT14246*' '${f//GEOT14246/GEOT15000}'
これはGEOT14246
ファイル名も置き換えます。両方のパラメータzmv
を再解析するには、両方のパラメータを囲む必要があります。
Linuxでは、bashまたはzshを介して次のものを使用できます。rename
代わりに。これはGEOT14246
各パスの最初のエントリのみを置き換えます。
rename GEOT14246 GEOT15000 /path/to/starting/dir/**/*GEOT14246*
**
Bashでは、まず再帰globを有効にする必要がありますshopt -s globstar
(この行をあなたのものに追加してください~/.bashrc
)。
LinuxディストリビューションがDebian、Ubuntu、またはその派生製品の場合rename
コマンドが異なります。次のいずれかの方法を使用します。
rename.ul GEOT14246 GEOT15000 /path/to/starting/dir/**/*GEOT14246*
rename 's/GEOT14246/GEOT15000/g' /path/to/starting/dir/**/*GEOT14246*