提取 n 和 m 分隔符之间的子字符串

提取 n 和 m 分隔符之间的子字符串

我想编写一个 for 循环来获取文件列表的第三个/到第四个之间的所有内容。.

我的尝试:

for mcool_file in ./input/*.mcool; do
    while IFS= read -r id; do
        id | cut -d \\ -f 4- -d_ -f1-4
        # Do something
    done;
done

追溯:

cut: only one type of list may be specified

输入

./../input/A001C007.hg38.nodups.pairs.mcool
./../input/A001C008.hg38.nodups.pairs.mcool

所需输出

A001C007
A001C008

答案1

for pathname in input/*.mcool; do
    basename "${pathname%%.*}"
done

这会迭代目录中input.mcool.对于 中的每个路径名$pathname,使用标准参数替换在第一个点处截断路径名(从 的值中${pathname%%.*}删除与模式匹配的最长后缀字符串),然后用于提取路径名的文件名部分。.*$pathnamebasename

测试:

$ tree
.
`-- input
    |-- A001C001.something.mcool
    |-- A001C002.something.mcool
    |-- A001C003.something.mcool
    |-- A001C004.something.mcool
    |-- A001C005.something.mcool
    |-- A001C006.something.mcool
    |-- A001C007.something.mcool
    |-- A001C008.something.mcool
    `-- A001C009.something.mcool

2 directories, 9 files
$ for pathname in input/*.mcool; do basename "${pathname%%.*}"; done
A001C001
A001C002
A001C003
A001C004
A001C005
A001C006
A001C007
A001C008
A001C009

这假设第一个点$pathname出现在文件名中,而不是路径名的目录部分中,这就是为什么我不以./.

basename但是我们可以通过首先调用它来扭转它,以允许目录路径中包含点:

for pathname in ./input/*.mcool; do
    name=$(basename "$pathname")
    printf '%s\n' "${name%%.*}"
done

要是我们知道我们要删除的后缀字符串正是字符串.something.mcool(或者.hg38.nodups.pairs.mcool在您的情况下),那么最好的解决方案可能是这样的

for pathname in ./input/*.something.mcool; do
    basename "$pathname" .something.mcool
done

...它用于basename从路径名中删除已知后缀并一次性返回路径名的文件名部分,一次一个路径名。

basename通过支持非标准-a和选项(用于处理多个文件并从每个文件中删除固定后缀字符串)的实现-s,如果没有太多文件需要处理,您甚至可以根本不使用循环:

$ basename -a -s .something.mcool ./input/*.something.mcool
A001C001
A001C002
A001C003
A001C004
A001C005
A001C006
A001C007
A001C008
A001C009

请参阅basename(1)您系统上的手册。

答案2

zsh

print -rC1 -- input/*.mcool(N:t:r:r:r:r)

:t修改器让你得到尾巴:r以及(删除文件的扩展名,就像在 csh 或 vim 中一样)。

或者:

set -o histsubstpattern
print -rC1 -- input/*.mcool(N:t:s/.*//)

或者:

(){print -rC1 -- ${@/.*}} input/*.mcool(N:t)

(使用 ksh-style${var/pattern[/replacement]}而不是 csh-style :s/foo/bar/,此处关于传递给匿名函数的参数,另请参阅${@%%.*}ksh)。

答案3

如果所有输入看起来像

./../input/A001C007.hg38.nodups.pairs.mcool

那么最简单的方法可能是:

start cmd:> sed -e 's+^./../input/++' -e 's/\..*$//' input
A001C007
A001C008

/如果您希望删除包括第三个在内的所有内容以及.下一个的所有内容

start cmd:> sed -r -e 's+^([^/]*/){3}++' -e 's/\..*$//' input
A001C007
A001C008

正如您所描述的一般解决方案必须计算.最多第三个的数量/

答案4

如果你知道是第三个/和第四个.,你也可以根据和作为分隔awk符来使用和定义字段:/.

awk -F'[./]' '{print $7}'

相关内容