我有一个脚本可以遍历文件并执行一些操作字符串替换插入日期。
#!/bin/bash
f="/tmp/file.txt" # with .txt extension
timestamp="$(date +%H%M%S)"
echo "${f%%.*}-$timestamp.${f#*.}"
它提供以下输出,这是正确的。
/tmp/file-220304.txt
但如果文件没有扩展名,脚本就会中断。
#!/bin/bash
f="/tmp/file" # no extension
timestamp="$(date +%H%M%S)"
echo "${f%%.*}-$timestamp.${f#*.}"
$ ./test.sh
/tmp/file-220359./tmp/file
是不是可以使用类似if未定义的方法${f:-not found}
来填充空白?f
我不知道如何用下面的方法解决上述问题。
#!/bin/bash
f="/tmp/file" # no extension
timestamp="$(date +%H%M%S)"
echo "${f%%.*}-$timestamp.${f#*.:-not found}"
结果:
$ ./test.sh
/tmp/file-221420./tmp/file
答案1
您还会遇到/tmp/dir.d/file
文件问题。
和zsh
:
#! /bin/zsh -
f="/tmp/file.txt" # with .txt extension
timestamp=${(%):-%D{%H%M%S}}
set -o extendedglob
extension=${(M)f%.[^./]#}
print -r -- ${f%$extension}-$timestamp$extension
使用标准sh
语法(也适用于 bash/zsh):
#! /bin/sh -
f="/tmp/file.txt" # with .txt extension
timestamp=$(date +%H%M%S)
case ${f##*/} in
(*.*) printf '%s\n' "${f%.*}-$timestamp.${f##*.}";;
(*) printf '%s\n' "$f-$timestamp";;
esac
使用bash
,您可以替换timestamp=$(date +%H%M%S)
为printf -v timestamp '%(%H%M%S)T'
以避免运行该date
命令。
答案2
如果您想要一个简单的解决方案,这里有一个有点不优雅但可行的解决方案的演示:
#!/bin/bash
# Test cases
FILE="/tmp/file"
# FILE="/tmp/file."
# FILE="/tmp/file.txt"
# FILE="/tmp/file.txt."
# TIMESTAMP="$(date +%H%M%S)"
printf -v TIMESTAMP '%(%H%M%S)T'
echo "${FILE%%.*}-${TIMESTAMP}.$([[ $FILE =~ \..*$ ]] && { echo "${FILE#*.}"; } || { echo "txt"; })"
.txt
如果缺少扩展名,上面的内容会添加到文件名中。
如果您不希望在缺少扩展名的情况下将默认扩展名添加到文件名中,请使用以下一行代码。
echo "${FILE%%.*}-${TIMESTAMP}$([[ $FILE =~ \..*$ ]] && { echo ".${FILE#*.}"; })"
答案3
为了简单起见
#!/bin/bash
f="/tmp/file"
timestamp="$(date +%H%M%S)"
out="${f}-${timestamp}";
[ "${f%.*}" != "${f##*.}" ] && out="${f%.*}-${timestamp}.${f##*.}";
echo "$out"
使其.
在路径中安全
dir=${f%/*};
file=${f##*/};
name=${file%.*};
suffix=${file##*.};
[ "$dir" != "$file" ] && dir=${dir}/ || unset dir;
[ "$name" != "$suffix" ] && suffix=.${suffix} || unset suffix;
echo "${dir}${name}-${timestamp}${suffix}"
如果您需要在一行中删除换行符,
请注意:我建议使用完整时间戳(日期+时间)以确保它是唯一的
答案4
并不是没有f
定义,而是在第一个点被删除之前该部分${f#*.}
的值。f
如果没有点,则不会删除任何内容,与${f#*.}
相同$f
。另外,由于它匹配第一的./foo.txt
点,您会遇到类似(它给出)的路径问题-181548./foo.txt
。
您需要测试是否${f#*.}
等于$f
或使用类似 的内容${f#${f%.*}}
,如果没有点分隔的后缀,它将变为空。对应的就是${f%.${f##*.}}
.尽管您仍然会再次遇到问题./file
。
问题./file
建议首先从路径中拆分文件名部分,然后从那里继续。
另一种方法是使用正则表达式。这适用于我测试的文件名:
#!/bin/bash
f=$1
timestamp="$(date +%H%M%S)"
re='^((.*/)?[^/.]+)(\.[^/]+)?$'
if [[ $f =~ $re ]]; then
echo "${BASH_REMATCH[1]}-${timestamp}${BASH_REMATCH[3]}"
fi
那是(.*/)?
——以斜杠结尾的可选路径;[^/.]+
-- 文件名的初始部分;(\.[^/]+)?
-- 可选扩展。