![如何在 shell 中仅提取父目录的“基本名称”?](https://linux22.com/image/93462/%E5%A6%82%E4%BD%95%E5%9C%A8%20shell%20%E4%B8%AD%E4%BB%85%E6%8F%90%E5%8F%96%E7%88%B6%E7%9B%AE%E5%BD%95%E7%9A%84%E2%80%9C%E5%9F%BA%E6%9C%AC%E5%90%8D%E7%A7%B0%E2%80%9D%EF%BC%9F.png)
我需要使用 shell 脚本通过某个“键”重命名几个文件。该密钥包括字符串以及我使用 .txt 文件获取的文件路径的提取部分find
。
我使用的是 Mac、OSX El Capitan 并使用 ZSH。这里是目录树:
├── 300x250
│ ├── 300x250-img-fallback.jpg
│ └── index/
├── 300x600
│ ├── 300x600-img-fallback.jpg
│ └── index/
├── 336x280
│ ├── 336x280-img-fallback.jpg
│ └── index/
└── 970x250
├── 970x250-img-fallback.jpg
└── index/
我需要重命名../指数/文件夹到../c2_[父文件夹名称]/。这就是我正在尝试的:
find . -type d -mindepth 2 -maxdepth 2 -exec sh -c 'echo -- mv "$0" "$(dirname "$0")"/"C2_"$(basename "$0/..")""' {} \;
不幸的是,这似乎不是获取basename
父母的正确方法。
find . -name "*index" -exec sh -c 'echo -- mv "$0" "$(dirname "$0")"/"C2_"$(basename "$0/..")""' {} \;
这只是一种变体,也不起作用(没有理由它应该:))。
我对 shell 脚本很陌生,并且正在尝试尽可能多地学习与 shell 无关一种方式,所以请忽略我目前正在使用 ZSH。
答案1
最好是使用zsh
的zmv
:
autoload zmv # best in ~/.zshrc
zmv -n '(*)/index' '$1/C2_$1'
(高兴时删除-n
)。
对于便携式(POSIXsh
) 解决方案:
for dir in */index; do
mv -i -- "$dir" "${dir%/*}/C2_${dir%/*}"
done
(-i
作为一个穷人的替代品来进行健全性检查zmv
)。
如果你想使用find
可移植(POSIXly),您需要忘记-mindepth
/ -maxdepth
,您可以将其替换为-path
和的组合-prune
:
LC_ALL=C find . -path './*/*' -prune -name index -exec sh -c '
for dir do
top=${dir#./}
top=${top%/*}
mv -i -- "$dir" "$top/C2_$top"
done' sh {} +
与其他两种方法的一个区别是,它不会遵循符号链接,并且还会index
在隐藏目录中查找。
它们利用了这里或网站上无数问答中描述的标准参数扩展运算符${var#pattern}
。${var%pattern}
POSIX shell 规范。
答案2
对于它的价值,你的尝试
find . -type d -exec sh -c 'echo -- mv "$0" "$(dirname "$0")"/"C2_"$(basename "$0/..")""' {} \;
似乎几乎可以工作,只是basename
不能解释点点。但获取dirname
应该给你父母的名字,你可以获取basename
其中的名字。像这样的东西:
$ mkdir -p 300x250/index 970x250/index
$ find . -name index -exec sh -c 'echo mv "$1" "$(dirname "$1")/C2_$(basename "$(dirname "$1")")"' sh {} \;
mv ./300x250/index ./300x250/C2_300x250
mv ./970x250/index ./970x250/C2_970x250
正如 Stéphane 提到的,后面的第一个参数sh -c "..."
被视为脚本的名称,它从上方进入$0
并与通常的位置参数不同$1
。后者有专门用于处理它们的工具,例如shift
和$@
,但它们不能处理$0
。
对于仅一个参数, using$0
可以工作,但由于 shell 的名称可能用于其他目的,因此最好sh
在那里设置一些合理的内容(例如 ),然后将实际参数放在后面。
答案3
从未工作过中兴,但下面的代码运行得很好巴什
SHW@SHW:/tmp/test1 # tree
.
├── 300x250
│ ├── 300x250-img-fallback.jpg
│ └── index
├── 300x600
│ ├── 300x600-img-fallback.jpg
│ └── index
├── 336x280
│ ├── 336x280-img-fallback.jpg
│ └── index
└── 970x250
├── 970x250-img-fallback.jpg
└── index
8 directories, 4 files
SHW@SHW:/tmp/test1 # for i in `find . -type d -name index`; do mv $i `dirname $i | cut -c3-`/c2_`dirname $i | cut -c3-`; done
SHW@SHW:/tmp/test1 # tree
.
├── 300x250
│ ├── 300x250-img-fallback.jpg
│ └── c2_300x250
├── 300x600
│ ├── 300x600-img-fallback.jpg
│ └── c2_300x600
├── 336x280
│ ├── 336x280-img-fallback.jpg
│ └── c2_336x280
└── 970x250
├── 970x250-img-fallback.jpg
└── c2_970x250
8 directories, 4 files