awk-regex编译失败



尝试用前瞻性(因此是awk而不是sed(替换正则表达式,该前瞻性删除所有点,保存最后一个点以保留扩展eg: (my.big.file.avi > my-big-file.avi)。这是我的小狂欢脚本:

#!/bin/bash
shopt -s globstar nullglob dotglob
for file in ./**/*.{mpg,mpeg,mkv,avi,mp4}; do
newFile=$(printf $file | awk '{gsub(/.(?=.*?.)/"-");}1')
#ffmpeg -i "$newFile" -vcodec copy -acodec aac "${newFile%.*}_AAC.mp4"
printf "${file} ---> ${newFile}n"
done

这给了我一个regular expression compile failed (missing operand)错误。。。

我看不见。有人能指出我的错误吗?

解决这个问题的任何部分都不需要awk或正则表达式;参数扩展就足够了。

#!/bin/bash
shopt -s globstar nullglob dotglob
for file in ./**/*.{mpg,mpeg,mkv,avi,mp4}; do
dirname=${file%/*}    # we don't want to change the directory name
filename=${file##*/}  # so split out just the filename
[[ $filename = *.*.* ]] || continue  # no compound extension? do nothing
file_start=${filename%.*}  # content up to last dot
file_ext=${filename##*.}   # content after last dot
newFile=${dirname}/${file_start//./-}.${file_ext} # combine the two
# okay, got what we need, now we can work with it
#ffmpeg -i "$newFile" -vcodec copy -acodec aac "${newFile%.*}_AAC.mp4"
printf '%s ---> %sn' "$file" "$newFile"
done

但是,如果希望使用正则表达式:

#!/bin/bash
shopt -s globstar nullglob dotglob
for file in ./**/*.{mpg,mpeg,mkv,avi,mp4}; do
[[ $file =~ ^(.*)/([^/]+)[.]([^/.]+)$ ]] || continue
dirname=${BASH_REMATCH[1]}
file_start=${BASH_REMATCH[2]}
file_ext=${BASH_REMATCH[3]}
newFile=${dirname}/${file_start//./-}.${file_ext}
printf '%s ---> %sn' "$file" "$newFile"
done

GNUAWK对lookahead的支持有限,即$表示行尾,>表示字尾。您的任务,即

删除所有点,保留最后一个点以保留扩展,例如:(my.big.file.avi > my-big-file.avi)

可以使用GNUAWK的函数来处理字符串,我会按照如下方式完成,让file.txt的内容是

my.big.file.avi
i-do-not-need-change.mp3
name-without-dot

然后

awk '{match($0,/[.][^.]*$/); print gensub(/[.]/,"-","g",substr($0,1,RSTART-1)) substr($0,RSTART)}' file.txt

输出

my-big-file.avi
i-do-not-need-change.mp3
name-without-dot

注意:我添加了2个测试用例。说明:首先使用match查找文字点([.](,然后是零个或多个(*(,而不是点([^.](,然后再查找行尾($(。这将把RSTART设置为行中最后一个点的位置。然后我用substr得到最后一个点之前的部分和最后一个点号和后面的字符。在第一部分中,我将所有点替换为-,在第二部分中我什么也不做,然后将它们与print连接起来。如果你想了解更多关于我使用的函数的信息,请阅读字符串函数文档。

(在GNU Awk 5.0.1中测试(

请记住,有些文件的扩展名为2个点,例如file.tar.gz,我的解决方案没有考虑到这一点。

(因此awk而非sed(

可怕的警告sed是图灵完备的。Ramiftion:它可以做任何其他图灵语言可以完成的事情。话虽如此,它确实意味着你应该使用它

awk中的两种详细方法:

[m/g/n]awk 'BEGIN { OFS =  "-"
FS = "[.]"
} ($NF="."$NF) 
&&  
sub(/-./,".")'

[m/g/n]awk 'sub(/.[^.]+$/,"&") + 
gsub(/./,    "-")     + 
sub(/-/, ".")    + 1'

我选择\0是因为空字节在几乎任何文件系统内的文件中都无效,这使它成为用作临时锚点的安全选择(甚至比awk SUBSEP更好,这在POSIX文件系统中并不违法(

还有一个远不如查尔斯优雅的替代品,但可能也能胜任。。。

echo my.big.file.avi | sed -E 's/./-/g;s/-([^-]+)$/.1/'
my-big-file.avi

最新更新