仅将文件名的部分内容转换为大写

仅将文件名的部分内容转换为大写

在 shell 脚本程序中,如果转换后的文件名尚不存在,我需要将文件名转换为大写。在这种特殊情况下,我只需将基本名称更改为大写,保留扩展名(如果有)不变。

我解决这个问题的想法是首先分别提取基本名称和扩展名,使用 tr命令将基本名称转换为大写,然后检查目录中是否存在更改的基本名称和扩展名。

如果它不存在,那么我将使用 mv 将原始文件名更改为大写基本名称。现在我认为这可以通过两种方式完成:首先使用expr,其次使用cutwith .(space-period-space) 作为分隔符。

如果我想用于expr提取基本名称(例如从文件名 -python1.pyphonelist),那么我写了这个:

basefile=`expr "$filename" : '\(.*\)\.*.*' ` 

我也使用了\.*那些没有任何扩展名的文件名,因为\.* 会忽略零次或多次出现的.,但此表达式expr无法正常工作。对于任何文件名,它都会按原样返回整个文件名。

谁能解释一下我哪里错了。另请建议我如何使用expr仅从文件名中提取扩展名。

答案1

如果 shell 是bash,则仅使用 bash 参数扩展:

file="aaa.bbb.dat"

name=${file%.*} # delete everything after last dot 
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything

echo "$upcase"
AAA.BBB.dat

尝试更困难的情况:

file="déjà vu . dat "
name=${file%.*} # delete everything after last dot 
ext=${file##*.} # delete everything up to last dot
upcase=${name^^*}.$ext # uppercase everything
echo ":$upcase:"

给出:

:DÉJÀ VU . dat :

所以:

  • 在使用结果之前不需要双引号
  • 即使对于非 ASCII 字符,大写似乎也可以

答案2

当组延伸多远存在模糊性时,正则表达式引擎首先优先考虑最长的匹配。对于任何文件名,\(.*\)匹配全名并\.*.*匹配空字符串。

您将需要两种情况:带或不带扩展名。另请注意,如果文件名以 开头.,则这不是扩展名的开头。

我不明白你为什么要使用expr. Shell 参数操作更容易。

在转换为大写时,请注意trLinux 上的实现不支持非 ASCII 语言环境。它只进行字节操作。例如echo accentué | tr a-z A-Z结果为ACCENTUé, not ACCENTUÉ。请改用 awk 等区域设置感知工具。在 bash 中,您可以使用${filename^^?},但在 sh 中不可用。确保您的脚本在文件名编码的正确区域设置中运行。

我假设文件名不包含目录部分。如果有,请先将其分开。

case $filename in
  ?*.*) # There is an extension
    base="${filename%.*}"; ext=".${filename##*.}";;
  *) # No extension
    base="$filename"; ext="";;
esac
upcased_base="$(printf %s. %base | awk '$0 = toupper($0)')"
upcased="${upcased_base%.}$ext"

然后删除尾随.部分,确保脚本正确处理文件名,并在扩展名之前添加换行符。如果没有这个,命令替换将删除尾随的换行符。如果您已经确保文件名不包含换行符,则不需要此操作。%s.$upcased_base

答案3

这是一个完全awk基于 - 的解决方案,您可以将以下行放入 shell 脚本中:

uppercasename="$(echo "$filename" | awk 'BEGIN{FS=OFS="."} NF==1{$1=toupper($1)} {for (i=1;i<NF;i++) $i=toupper($i)} 1')"

这将使用.as 字段分隔符用于输入和输出并且,如果只找到一个字段,则将其转换为大写,在所有其他情况下,将除最后一个字段之外的所有字段都转换为大写。然后它打印结果(这就是 的含义1,它是 的简写符号{print})。

如果您正在使用bash,您可以去掉管道并将其声明为

uppercasename="$(awk 'BEGIN{FS=OFS="."} NF==1{$1=toupper($1)} {for (i=1;i<NF;i++) $i=toupper($i)} 1' <<< "$filename")"

使用此处字符串。

请注意,这是这样设计的,以便在文件名以 结尾的边界情况下.(如 中)myfile.this.txt.,它会将其视为“空但存在的后缀”并将其转换为MYFILE.THIS.TXT..另外,如果文件名开始如果带有.且没有其他扩展名(如.myfile),则会将其保留为小写。

相关内容