如何 GREP 文件名的子字符串以重命名文件?
How to GREP a substring of a filename for renaming files?
我有很多文件以 example1_partofEx1A_individualfile_name.fil
命名。
我已经将文件组织成一个目录结构,所以路径是 ./example1/partofEx1A/example1_partofEx1A_individualfile_name.fil
。
我正在尝试编写一个可以从文件名中删除不必要信息的脚本。我基本上想 grep 'individualfile' 部分,这样我就可以使用循环和 mv.
我没有编写脚本的经验,只有一些 matlab 经验。使用 ubuntu 或 macOS。有什么建议吗?
假设三部分(前两个删除,第三个保留)总是用下划线分隔,这可能是一个可能的解决方案:
for f in /path/to/rootdir/*; do
if [[ -f $f ]]; then
mv "$f" "$(echo "$f" | sed "s/\/.*_.*_/\//")"
fi
done
其中 /path/to/rootdir
是您的结构的根目录。
可能是这样的:
#!/bin/bash
cd /path/to/rootdir || exit
for file in *.fil;do
IFS=_ read dir1 dir2 individual <<<"$file"
if [ "$individual" ] ;then
test -d "$dir1/$dir2" || mkdir -p "$dir1/$dir2"
# mv -v "$file" "$dir1/$dir2/$individual"
mv -vt "$dir1/$dir2" "$file"
fi
done
根据 Charles Duffy's comment 的建议,我已将 -p
标志添加到 mkdir
以防止竞争条件。
#!/usr/bin/env bash
for f in ./*/*/*; do
[[ $f =~ ^[.]/([^/]+)/([^/]+)/(.*) ]] || continue
dir1=${BASH_REMATCH[1]}
dir2=${BASH_REMATCH[2]}
filename=${BASH_REMATCH[3]}
[[ $filename = "${dir1}_${dir2}_"* ]] || continue
new_name=${filename#"${dir1}_${dir2}_"}
mv -- "$f" "${dir1}/${dir2}/$new_name"
done
测试如下:
testdir="$(mktemp -d)"
cd "$testdir" || exit
mkdir -p ./dirA/dirB
touch dirA/dirB/dirA_dirB_hello_world.txt
touch dirA/dirB/other_content_here.txt
for f in ./*/*/*; do
[[ $f =~ ^[.]/([^/]+)/([^/]+)/(.*) ]] || continue
dir1=${BASH_REMATCH[1]}
dir2=${BASH_REMATCH[2]}
filename=${BASH_REMATCH[3]}
[[ $filename = "${dir1}_${dir2}_"* ]] || continue
new_name=${filename#"${dir1}_${dir2}_"}
mv -- "$f" "${dir1}/${dir2}/$new_name"
done
...目录包含:
./dirA
./dirA/dirB
./dirA/dirB/hello_world.txt
./dirA/dirB/other_content_here.txt
我有很多文件以 example1_partofEx1A_individualfile_name.fil
命名。
我已经将文件组织成一个目录结构,所以路径是 ./example1/partofEx1A/example1_partofEx1A_individualfile_name.fil
。
我正在尝试编写一个可以从文件名中删除不必要信息的脚本。我基本上想 grep 'individualfile' 部分,这样我就可以使用循环和 mv.
我没有编写脚本的经验,只有一些 matlab 经验。使用 ubuntu 或 macOS。有什么建议吗?
假设三部分(前两个删除,第三个保留)总是用下划线分隔,这可能是一个可能的解决方案:
for f in /path/to/rootdir/*; do
if [[ -f $f ]]; then
mv "$f" "$(echo "$f" | sed "s/\/.*_.*_/\//")"
fi
done
其中 /path/to/rootdir
是您的结构的根目录。
可能是这样的:
#!/bin/bash
cd /path/to/rootdir || exit
for file in *.fil;do
IFS=_ read dir1 dir2 individual <<<"$file"
if [ "$individual" ] ;then
test -d "$dir1/$dir2" || mkdir -p "$dir1/$dir2"
# mv -v "$file" "$dir1/$dir2/$individual"
mv -vt "$dir1/$dir2" "$file"
fi
done
根据 Charles Duffy's comment 的建议,我已将 -p
标志添加到 mkdir
以防止竞争条件。
#!/usr/bin/env bash
for f in ./*/*/*; do
[[ $f =~ ^[.]/([^/]+)/([^/]+)/(.*) ]] || continue
dir1=${BASH_REMATCH[1]}
dir2=${BASH_REMATCH[2]}
filename=${BASH_REMATCH[3]}
[[ $filename = "${dir1}_${dir2}_"* ]] || continue
new_name=${filename#"${dir1}_${dir2}_"}
mv -- "$f" "${dir1}/${dir2}/$new_name"
done
测试如下:
testdir="$(mktemp -d)"
cd "$testdir" || exit
mkdir -p ./dirA/dirB
touch dirA/dirB/dirA_dirB_hello_world.txt
touch dirA/dirB/other_content_here.txt
for f in ./*/*/*; do
[[ $f =~ ^[.]/([^/]+)/([^/]+)/(.*) ]] || continue
dir1=${BASH_REMATCH[1]}
dir2=${BASH_REMATCH[2]}
filename=${BASH_REMATCH[3]}
[[ $filename = "${dir1}_${dir2}_"* ]] || continue
new_name=${filename#"${dir1}_${dir2}_"}
mv -- "$f" "${dir1}/${dir2}/$new_name"
done
...目录包含:
./dirA
./dirA/dirB
./dirA/dirB/hello_world.txt
./dirA/dirB/other_content_here.txt