这很简单,已经被询问/回答过很多次,但是当文件位于不同目录中时却并非如此。我想做这个: Renaming part of a filename,但文件位于不同的子目录中。
这是我尝试过的:
for f in */*run?.t; do mv -i -- "$f" "${f//subset/subset5}"; done
,但它也会尝试重命名目录(因为子集也位于目录名称中),然后由于未找到该目录名称而出错。我想念什么?
以下是常规目录结构:
Gene1_subset/
Gene1file_subset.run1.t
Gene1file_subset.run2.t
Gene2_subset/
Gene2file_subset.run1.t
Gene2file_subset.run2.t
这就是我想要的:
Gene1_subset/
Gene1file_subset5.run1.t
Gene1file_subset5.run2.t
Gene2_subset/
Gene2file_subset5.run1.t
Gene2file_subset5.run2.t
但是它也会尝试重命名目录,因此您会收到错误消息:
cannot move Gene1_subset/Gene1file_subset.run1 to Gene1_subset5/Gene1file_subset5.run1 : No such file or directory
答案 0 :(得分:0)
您可以检查文件是否为目录,如果不是,则将其重命名。
例如,如果[ -d FILE ]
存在并且是目录,true
将返回FILE
。
不要尝试从根目录移走所有内容,而是循环所有目录,并为每个目录循环所有文件。
E.G。
#!/bin/bash
rename() {
for dir in *; do
if [ -d "${dir}" ]; then
cd "${dir}"
for f in *run?; do
! [ -d "${f}" ] && mv -i -- "${f}" "${f//subset/subset5}"
done
cd ..
fi
done
}
rename || exit $?
exit 0
答案 1 :(得分:0)
$ mkdir -p Gene1_subset Gene2_subset
$ touch Gene1_subset/Gene1file_subset.run1 Gene1_subset/Gene1file_subset.run2 Gene2_subset/Gene2file_subset.run1 Gene2_subset/Gene2file_subset.run2
我认为一切都归结于找到合适的正则表达式。在这里,我将字符串subset.run
替换为subset5.run
:
$ find . -name '*.run[0-9]' -exec sh -c 'mv -v "{}" "$(echo {} | sed "s/subset\.run/subset5\.run/")"' \;
renamed './Gene2_subset/Gene2file_subset.run2' -> './Gene2_subset/Gene2file_subset5.run2'
renamed './Gene2_subset/Gene2file_subset.run1' -> './Gene2_subset/Gene2file_subset5.run1'
renamed './Gene1_subset/Gene1file_subset.run2' -> './Gene1_subset/Gene1file_subset5.run2'
renamed './Gene1_subset/Gene1file_subset.run1' -> './Gene1_subset/Gene1file_subset5.run1'
但是我们可以例如使用basename
和dirname
从文件名和目录中剥离路径,然后仅对文件名运行sed:
$ find . -name '*.run[0-9]' -exec sh -c "mv -v \"{}\" \"\$(dirname \"{}\")/\$(basename \"{}\" | sed 's/subset/subset5/')\"" \;
renamed './Gene2_subset/Gene2file_subset.run2' -> './Gene2_subset/Gene2file_subset5.run2'
renamed './Gene2_subset/Gene2file_subset.run1' -> './Gene2_subset/Gene2file_subset5.run1'
renamed './Gene1_subset/Gene1file_subset.run2' -> './Gene1_subset/Gene1file_subset5.run2'
renamed './Gene1_subset/Gene1file_subset.run1' -> './Gene1_subset/Gene1file_subset5.run1'
逃避一点学习。这可能会让您更容易理解:
for f in */*run?; do f2=$(basename "$f"); mv -vi -- "$f" "$(dirname "$f")/${f2//subset/subset5}"; done
renamed 'Gene1_subset/Gene1file_subset.run1' -> 'Gene1_subset/Gene1file_subset5.run1'
renamed 'Gene1_subset/Gene1file_subset.run2' -> 'Gene1_subset/Gene1file_subset5.run2'
renamed 'Gene2_subset/Gene2file_subset.run1' -> 'Gene2_subset/Gene2file_subset5.run1'
renamed 'Gene2_subset/Gene2file_subset.run2' -> 'Gene2_subset/Gene2file_subset5.run2'
答案 2 :(得分:0)
类似的事情应该做:
#!/usr/bin/env bash
shopt -s extglob globstar nullglob
for f in **/*_subset.run+([0-9]).t; do
tmp=${f##*_}
mv -i -- "$f" "${f%_*}_${tmp/et/et5}"
done
如果文件严格遵循结构,则只需将代码更改为:
mv -i -- "$f" "${f/file_subset/file_subset5}"