S_1004_DKDL220006264-1A_HLGLFDSX3_L4_cleaned_1_fastqc.html
S_1004_DKDL220006264-1A_HLGLFDSX3_L4_cleaned_1_fastqc.zip
S_1004_DKDL220006264-1A_HLGLFDSX3_L4_cleaned_2_fastqc.html
S_1004_DKDL220006264-1A_HLGLFDSX3_L4_cleaned_2_fastqc.zip
S_1006_DKDL220006298-1A_HKFTLDSX3_L1_cleaned_1_fastqc.html
S_1006_DKDL220006298-1A_HKFTLDSX3_L1_cleaned_1_fastqc.zip
S_1006_DKDL220006298-1A_HKFTLDSX3_L1_cleaned_2_fastqc.html
字符串
上面是文件夹中文件的名称。我想从右数第二个_
和左数第二个_
之间删除。这样输出看起来像
S_1004__1_fastqc.html
S_1004__1_fastqc.zip
S_1004__2_fastqc.html
S_1004__2_fastqc.zip
S_1006__1_fastqc.html
S_1006__1_fastqc.zip
S_1006__2_fastqc.html
型
如何使用bash实现这一点?
我尝试了以下代码:
for file in *.html *.zip; do
new_name=$(echo "$file" | sed 's/_[^_]*_/_/')
mv "$file" "$new_name"
done
型
但它并没有按照我想要的方式工作。
5条答案
按热度按时间o75abkj41#
您不需要
sed
来执行此操作(但请参阅最后的解释,了解尝试失败的原因以及工作的sed
命令)。使用足够新的
bash
([[ string =~ regexp ]]
和BASH_REMATCH
至少为3.0):字符串
一个老的bash:
型
注意:
set -f; ...; set +f
暂时禁止路径名扩展,因为您的文件名可能包含glob运算符(*
,?
,[...]
)。尝试失败的原因是
sed
试图从左到右匹配正则表达式(并且是贪婪的)。在sed 's/_[^_]*_/_/'
中,最左边的匹配被替换。如果文件名为S_1004_DKDL220006264-1A_HLGLFDSX3_L4_cleaned_1_fastqc.html
,则匹配部分为_1004_
(最左边),结果为S_DKDL220006264-1A_HLGLFDSX3_L4_cleaned_1_fastqc.html
。如果你真的想使用
sed
,你可以尝试:型
k5ifujac2#
新的文件名可以使用POSIX shell中内置的字符串操作功能来计算。尝试以下Shellcheck-clean代码:
字符串
bash
和dash
(/bin/sh
引用的最常见的shell)对此进行了测试。[ -f "$file" ] || continue
如果当前匹配的文件不是常规文件,则跳过当前匹配的文件。这可能是因为它是其他文件类型(例如,目录或fifo),或者因为没有文件匹配该模式(因此$file
的文字值为*_*_*_*_*.*
)。${file##*.}
、${file*.*}
和其他字符串操作的解释,请参见POSIX Shell Command Language文档的参数扩展部分。echo
。9o685dep3#
尝试使用awk而不是sed
字符串
ve7v8dk24#
如果你正在寻找一个
awk
脚本来实现上述解决方案。我会将字段分隔符设置为_
,然后打印所需的字段(第一个,第二个,最后一个,但第二个和最后一个字段),第一个,第二个和最后一个由_
分隔,最后一个,但第二个由__
分隔。NF
是预定义的变量。以下是示例:
字符串
脚本演示
替代方案(使用
perl
):型
脚本演示
rlcwz9us5#
如果你想给予一下Perl一行程序:
字符串
-e
:允许您在命令行上输入程序。-p
:假设程序有一个循环,如:while(<>){...}。它也会打印这行,所以print语句是不必要的(将它与下面的-n进行比较)。-n
:假设一个while循环while(<>){...}。但是除非你显式地打印它,否则它不会打印该行。这不是程序的一部分,但是我在这里把它和-p进行比较。如果你用-n写了同样的一行程序,你的程序会像这样:perl -ne '{$_ =~ s/(^.+_\d+_).+(_\d_fastqc.+)/\1\2/; print $_}' file
的值。该值为$_
:这是Perl的默认变量。实际上,您可以省略它,并将其写成:perl -pe '{s/(^.+_\d+_).+(_\d_fastqc.+)/\1\2/}' file
个s///
:这是Perl的替换运算符。例如,s/old/new/ #Replaces old with new.
剩下的就是正则表达式了(我相信你可以用很多不同的方法来写这一部分,下面是一种方法):
s/(^.+_\d+_).+(_\d_fastqc.+)/\1\2/
:这将匹配每行。(^.+_\d+_)
:从行首到第二个下划线得结尾进行捕获.它被\1捕获.(_\d_fastqc.+)
:匹配从左起第二个下划线右侧的任何内容。由\2捕获。\1
捕获第一组()
的内容,而\2
捕获第二组()
的内容。要了解它们的作用,最好的方法是只使用\1或\2运行。
简而言之:您只使用行的捕获部分替换整行,因此非捕获文本将被删除