如何用分隔符分割字符串并在bash中交换子字符串的位置?

Posted

技术标签:

【中文标题】如何用分隔符分割字符串并在bash中交换子字符串的位置?【英文标题】:How to split the string with delimiter and swap the substring's position in bash? 【发布时间】:2021-12-17 05:08:35 【问题描述】:

这是场景,

例如,我们有一个名为 a.txt、b.txt、...z.txt 的文件列表。目标是将它们命名为 txt.a,txt.b,txt.c.....txt.z

输入:

a.txt
b.txt
c.txt
...
...
z.txt

输出:

txt.a
txt.b
txt.c
...
...
txt.z

我尝试了这种单线并获得了所需的输出。 单线

ls -l *.txt | awk -F " " 'print $9' | awk -F "." 'str1 = $2; str2 = "."; str3 = $1; str4 = str1 str2 str3; print str4'

问: 如果 bash 中还有更好的方法来实现此功能,有人可以帮忙吗?

【问题讨论】:

【参考方案1】:

假设/理解:

目标是重命名文件(问题提到了Goal is to name them as ...,但没有提到mv 命令...???) 所有文件名都包含一个句点 我们想要切换文件名的前/后部分以创建新文件名 不存在使用新文件名的文件(例如,我们目前没有名为 a.txttxt.a 的文件)

使用parameter expansion 的一个想法可以让我们消除子流程调用的开销:

for fname in *.txt
do
    new_fname="$fname#*..$fname%.*"
    echo mv "$fname" "$new_fname"
done

对于文件名 a.txtb.txtc.txt,这会生成:

mv a.txt txt.a
mv b.txt txt.b
mv c.txt txt.c

一旦 OP 对结果感到满意,就可以删除 echo,脚本应该执行实际的 mv/rename。

【讨论】:

【参考方案2】:

如果基于 Perl 的 rename 命令可用,请尝试:

rename 's/^([^.]+)\.([^.]+)$/$2.$1/' *.txt

重命名规则是 Perl 的替换表达式 使用正则表达式:

^ 匹配(锚定)文件名的开头。 ([^.]+) 匹配除点之外的任何字符序列。 然后匹配的子字符串可以通过 $1 引用,因为周围的括号。 \. 匹配一个点。 ([^.]+) 再次。现在被$2引用。 $ 匹配(锚定)文件名的结尾。 $2.$1 是替换部分,交换两个子串 穿过点。

请注意,有两个名为 rename 的不同命令。一个是 基于Perl,其他的不是。您可以通过以下方式识别它 看到手册页。如果它包含单词perlexpr,它是基于Perl 的。

【讨论】:

【参考方案3】:
for f in [a-z].txt; do mv "$f" "txt.$f%.*"; done

【讨论】:

【参考方案4】:

如果文件名是最后一列,并且文件有一个点,您可以使用单个 awk 在一个点上拆分并反向打印 2 个部分。

使用$NF 匹配最后一个字段。

ls -l *.txt | awk '

    split($NF, a, ".")
    print a[2] "." a[1]
'

如果拆分后应该有2个部分,您可以查看拆分结果:

ls -l *.txt | awk '

    n=split($NF, a, ".")
    if (n == 2) print a[2] "." a[1]
'

或者作为替代方案,使用 sed 和反向打印的 2 个捕获组,使用 ls -1 每行列出一个文件。

ls -1 *.txt | sed -E 's/^([^.]+)\.([^.]*)$/\2.\1/'

【讨论】:

Don't use ls in scripts. @tripleee 谢谢,读得很好。我没有意识到这一点。

以上是关于如何用分隔符分割字符串并在bash中交换子字符串的位置?的主要内容,如果未能解决你的问题,请参考以下文章

如何用shell提取文件中指定的字符串

如何用逗号和空格java分割表达式

C语言如何实现分割字符串为一个个单独的字符并保存

Java split()函数,要分割的字符串中没有指定的分隔符,返回啥结果

如何用字符串中最后找到的数字分割字符串?

如何用括号外的逗号分割字符串?