我知道这个主题已经被讨论过(在这里和其他地方),但我请求你宽容,因为我正在尝试通过 bash 脚本艺术找到我的方法;
我需要解决以下问题
鉴于我有:
目录1
- 文件1
- 文件2
- 等等...
目录2
- 文件1
- 文件2
- 等等...
我想重命名文件以便
目录1
- 目录1_文件1
- 目录1_文件2
- dir1_等等...
目录2
- 目录2_文件1
- 目录2_文件2
- dir2_等等...
到目前为止,我已经设法制定出以下“探索性”bash 脚本
for d in `ls -d */`
do
#echo "$d"
pre="${d:0:-1}"
#echo "$pre"
#cd "${d}"
pushd "${d}"
for f in *.jp2
do
#echo "${f}"
echo "${pre}_${f}"
done
#cd -
#popd
done
除了错误消息之外,它似乎工作(相当)正常
line 9: pushd: dir2/: No such file or directory
其中 dir2 是 for 循环扫描的最后一个目录的名称...
有什么帮助吗?我缺少什么?
答案1
而不是尝试cd
来回进入目录(popd
并且pushd
主要用于交互使用):
#!/bin/sh
for name in */*; do
[ ! -f "$name" ] && continue
dir="$( basename "$( dirname "$name" )" )"
newname="$dir/${dir}_${name##*/}"
if [ ! -e "$newname" ]; then
echo mv "$name" "$newname"
fi
done
这将迭代当前目录中所有目录中的所有名称。它将跳过非文件并将目录基本名称(没有路径的目录名称)提取到dir
.然后,它使用(可以替换为)中的路径名的基本名称部分$newname
为该文件构造一个新的文件名。$dir
$name
${name##*/}
$( basename "$name" )
如果尚未使用新名称,则文件将被重命名。
echo
一旦您确认它应该做正确的事情,请删除它以实际重命名文件。
要在另一个目录中执行一组操作然后返回,请使用
( cd dir
action
action
action )
更改的目录不会影响( ... )
.
也可以看看:为什么*不*解析`ls`?
答案2
你说“dir2是for循环扫描的最后一个目录的名称”,但它实际上是第二最后,不是吗?它失败了,因为你已经popd
注释掉了。在第一次循环迭代结束时,您仍然处于“in”状态dir1
,因此您的尝试pushd dir2
实际上是在寻找dir1/dir2
;即,dir2
在 内dir1
。
如果您有七个目录,那么最后六个目录将会失败。
您提出了这样的担忧:“取消注释 popd 会导致其他不需要的后果,...即,如果 for 循环迭代的目录(同一级别)中存在文件(不是目录),情况会怎样”。出色地,
- 这种逻辑就像是在说:“如果我除了穿左鞋之外还穿右鞋,那么我的枪就多了一个目标,所以我更有可能用右脚开枪自杀。”这毫无意义。只穿
pushd
而不遵循popd
(尤其是循环)比只穿一只鞋要错误得多。 - 由于您使用的是
*/
,因此您只会获得目录。- 但 Kusalananda 是对的:你应该使用
for d in */
而不是for d in `ls -d */`
.
- 但 Kusalananda 是对的:你应该使用
更好的是,你可以做类似的事情
for d in * do … if [ -d "$d" ] then pushd "$d" for f in *.jp2 do … done popd fi done
或者
for d in * do … if pushd "$d" 2> /dev/null then for f in *.jp2 do … done popd fi done
所以你不要尝试将非目录视为目录。