如何用分隔符分割字符串并在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.txt
和 txt.a
的文件)
使用parameter expansion 的一个想法可以让我们消除子流程调用的开销:
for fname in *.txt
do
new_fname="$fname#*..$fname%.*"
echo mv "$fname" "$new_fname"
done
对于文件名 a.txt
、b.txt
和 c.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 usels
in scripts.
@tripleee 谢谢,读得很好。我没有意识到这一点。以上是关于如何用分隔符分割字符串并在bash中交换子字符串的位置?的主要内容,如果未能解决你的问题,请参考以下文章