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

How to split the string with delimiter and swap the substring's position in bash?

是这样的场景,

例如,我们有一个名为 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 }' | awk -F "." '{str1 = ; str2 = "."; str3 = ; str4 = str1 str2 str3; print str4}'

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

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

使用 $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/^([^.]+)\.([^.]*)$/./'

Assumptions/understanding:

  • objective 是重命名文件(问题提到 Goal is to name them as ... 但没有提到 mv 命令.. .???)
  • 所有文件名都包含一个句点
  • 我们想要切换文件名的 before-period/after-period 部分以创建新文件名
  • 不存在具有新文件名的文件(例如,我们目前没有名为 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/重命名。

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

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

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

  • ^ 匹配(锚定)文件名的开头。
  • ([^.]+) 匹配除点之外的任何字符的序列。 然后匹配的子串可以被</code>引用,因为周围有括号。</li> <li><code>\. 匹配一个点。
  • 再次
  • ([^.]+)。现在由 </code>.</li> 引用 <li><code>$ 匹配(锚定)文件名的末尾。
  • .是替换部分,将两个子串互换 点对点。

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

for f in [a-z].txt; do mv "$f" "txt.${f%.*}"; done