我有一个很长的文件夹列表,具有以下命名约定
ABS1789_2563-01
ABS1789_2563-02
ABS1789_2563-02
.
.
.
如何使用 bash 在 ABS 和 1789 之间添加“-”,然后在 1789 和 2563 之间用“-”替换“_”?
答案1
IFS="\n" # Handle files with spaces in the names
for file in ABS*; do
newfile="${file/ABS/ABS-}" # Add the hyphen following ABS
newfile="${newfile/_/-}" # Change the underscore to a hyphen
mv "$file" "$newfile" # Make the change
done
根据托尼下面的评论,更通用的版本可能如下:
IFS="\n" # Handle files with spaces in the names
for file in ABS*; do
newfile="${file/foo/bar}" # Replace foo with bar
newfile="${newfile/baz/quux}" # Replace baz with quux (repeat as needed)
if [[ "$file" == "$newfile" ]]; then
echo "Not renaming $file - no change decreed."
elif [[ -f "$newfile" ]]; then
echo "Not renaming $file - $newfile already exists."
else
mv -- "$file" "$newfile" # Make the change
fi
done
答案2
合适的答案取决于名称的变化。如果假设字段宽度恒定,则可以使用 shell 的内置参数替换来转换名称。范围相对有限。
更有趣的是在以下位置使用字符类sed
:
newname=$(echo "$oldname" | sed -e 's/^\([[:alpha:]]\+\)\([[:digit:]]\+\)_/\1-\2-/')
也就是说,在前导字母前缀后添加破折号,然后在以下划线结尾的数字后更改那到破折号。
与使用参数替换的可能解决方案不同,此方法允许字母前缀和数字的任何(非零)长度。所以你可以将其作为输入:
ABS1789_2563-01
ABS1789_2563-02
ABS1789_2563-02
ABSOLUTE1789_2563-01
ABSURD1789_2563-02
ABSOLVE1789_2563-02
PREFIX1793939389_2563-02
将其放入脚本中
#!/bin/sh
for oldname in `cat foo4.txt`
do
newname=$(echo "$oldname" | sed -e 's/^\([[:alpha:]]\+\)\([[:digit:]]\+\)_/\1-\2-/')
echo "$oldname ->$newname"
done
给出这个输出(在合适的循环中):
ABS1789_2563-01 ->ABS-1789-2563-01
ABS1789_2563-02 ->ABS-1789-2563-02
ABS1789_2563-02 ->ABS-1789-2563-02
ABSOLUTE1789_2563-01 ->ABSOLUTE-1789-2563-01
ABSURD1789_2563-02 ->ABSURD-1789-2563-02
ABSOLVE1789_2563-02 ->ABSOLVE-1789-2563-02
PREFIX1793939389_2563-02 ->PREFIX-1793939389-2563-02
答案3
如果一切开始于ABS1789_2563-
for f in ABS*; do mv "$f" ABS-1789-2563-${f:13}; done
这里
ABS-1789-2563-
假设所有文件夹都以以下内容开头,则只是硬编码ABS1789_2563-。
${f:13}
从偏移量 13 开始扩展到参数末尾$f
- 通常称为子串。在bash中子串扩展。
看3.5.3 Shell参数扩展, 部分:
${parameter:offset} ${parameter:offset:length}