在Bash中重命名特定模式的文件

3
我有以下文件和目录:
/tmp/jj/
/tmp/jj/ese
/tmp/jj/ese/2010
/tmp/jj/ese/2010/test.db
/tmp/jj/dfhdh
/tmp/jj/dfhdh/2010
/tmp/jj/dfhdh/2010/rfdf.db
/tmp/jj/ddfxcg
/tmp/jj/ddfxcg/2010
/tmp/jj/ddfxcg/2010/df.db
/tmp/jj/ddfnghmnhm
/tmp/jj/ddfnghmnhm/2010
/tmp/jj/ddfnghmnhm/2010/sdfs.db

我希望将所有的2010目录重命名为其父目录,然后tar所有.db文件...
我尝试过的方法是:
#!/bin/bash

if [ $# -ne 1 ]; then
    echo "Usage: `basename $0` <absolute-path>"
    exit 1
fi

if [ "$(id -u)" != "0" ]; then
    echo "This script must be run as root" 1>&2
    exit 1
fi
rm /tmp/test

find $1 >> /tmp/test
for line in $(cat /tmp/test)
do
    arr=$( (echo $line | awk -F"/" '{for (i = 1; i < NF; i++) if ($i == "2010") print $(i-1)}') )
    for index in "${arr[@]}"
    do
    echo $index #HOW TO WRITE MV COMMAND RATHER THAN ECHO COMMAND?
    done
done

1) 结果是:

ese


dfhdh


ddfxcg


ddfnghmnhm

但是应该是这样的:
ese
dfhdh
ddfxcg
ddfnghmnhm

2) 如何将所有2010目录重命名为其父目录?我的意思是如何执行此操作(我想在循环中执行,因为有大量目录):

mv /tmp/jj/ese/2010 /tmp/jj/ese/ese
mv /tmp/jj/dfhdh/2010 /tmp/jj/dfhdh/dfhdh
mv /tmp/jj/ddfxcg/2010 /tmp/jj/ddfxcg/ddfxcg
mv /tmp/jj/ddfnghmnhm/2010 /tmp/jj/ddfnghmnhm/ddfnghmnhm
4个回答

2

你可以使用 find 命令来确定一个目录是否包含名为 2010 的子目录,并执行 mv 命令进行移动操作:

find /tmp -type d -exec sh -c '[ -d "{}"/2010 ] && mv "{}"/2010 "{}"/$(basename "{}")' -- {} \;

我不确定你是否还有其他问题,但这将完成你在问题末尾列出的内容,即:

mv /tmp/jj/ese/2010 /tmp/jj/ese/ese

and so on...


谢谢。有两个问题。有了您的答案,我该如何编辑我的脚本?请问您能帮我做吗? - MLSC
如果我正确理解了问题,那么您需要替换在上面提到的find命令中传递给脚本的第一个参数。 - devnull
1
find{} 占位符不应该以那种方式使用。想象一下,如果有一个带引号和恶意命令的文件,你就完了!你 sh 命令中所有的 {} 都应该替换为 $1 - gniourf_gniourf

2
可以使用grep -P进行操作:
grep -oP '[^/]+(?=/2010)' file
ese
ese
dfhdh
dfhdh
ddfxcg
ddfxcg
ddfnghmnhm
ddfnghmnhm

1
首先,只迭代你感兴趣的目录,并避免临时文件:
for d in $(find $1 -type d -name '2010') ; do

然后你可以使用basenamedirname来提取该目录名称的部分并重新构建所需的目录。类似这样:

  b="$(dirname $d)"
  p="$(basename $b)"
  echo mv "$d" "$b/$p" 

你可以使用Shell字符串替换操作来代替basename/dirname。

我知道我的朋友,但结果只打印“mv etc等”,我应该删除“echo”吗? - MLSC
1
在测试并验证其工作正常之前,不应该删除回显。 - Mat
很好...非常棒的回答...我移除了echo,然后它在我朋友的机器上就正常工作了... - MLSC
1
永远不要像这样使用for循环for d in $(find...); do ... done来处理目录/文件名,因为如果它们包含空格,它将失败。相反,始终使用find ... | while IFS= read -r d; do ... done。即使它们包含换行符,仍然存在问题,但这种情况发生的可能性要小得多,如果出现这种情况,请切换到find -print0 | xargs -0 - Ed Morton
@MortezaLSC:如果路径包含空格(或换行符、制表符等),我写的代码是不安全的。如果您确定这永远不会发生,那么就没问题了。否则,devnull或Ed Morton的答案更好。 - Mat
显示剩余2条评论

1
这应该是接近的:

find "$1" -type d -name 2010 -print |
while IFS= read -r dir
do
    parentPath=$(dirname "$dir")
    parentDir=$(basename "$parentPath")
    echo mv "$dir" "$parentPath/$parentDir"
done

测试后删除echo。如果您的目录名称可能包含换行符,请查看find-print0选项和xargs-0选项。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接