使用 sed 将开头出现的所有匹配项替换为匹配数量的替换字符串

使用 sed 将开头出现的所有匹配项替换为匹配数量的替换字符串

我希望以这样的方式操作 $tree --noreport$ 的输出,即用匹配数量的空格替换每行上的前导框绘制字符和空格。如果我要编写匹配这些字符的模式,那就是^\\(\u2500\\|\u2514\\|\u251C\\| \\)*\u2500.该字符串将被包裹起来,$'...'因为 sed 无法识别 Unicode 转义序列。此模式出现在tree --noreport除第一行之外的输出的每一行上。每个匹配字符串中的每个字符都需要替换为空格。

输入示例:

.
├── docs
│   ├── jokes
│   │   └── knock_knock.txt
│   └── work
├── images
└── .profile

输出示例:

.
    docs
        jokes
            knock_knock.txt
        work
    images
    .profile

我现在意识到,出于我的目的,我需要消除文件或文件夹名称开始位置的歧义(文件或文件夹名称可能以一个或多个空格开头),因此输出实际上应该类似于:

.
    /docs
        /jokes/
            /knock_knock.txt
        /work
    /images
    /.profile

我提供的模式的末尾\u2500实际上区分了树的格式和文件/文件夹名称的开头。

答案1

您可以在循环中一次替换一个,如下所示:

tree --noreport | sed $'
  :1
    s/^\\( *\\)\\([\ua0\u2500\u2502\u2514\u251C]\\)\\([\ua0\u2500\u2502\u2514\u251C ]*\u2500 \\)/\\1 \\3/
  t1
  s|\u2500 |  /|'

(您至少错过了\ua0(不间断空格)和\u2502(也在您的示例中显示),它们至少出现在我的版本的输出中)。tree

如果有些文件的名称"─ "前面可能包含其中一些字符,那就被愚弄了。

另一种方法(假设您确实想要插入/且您调用的目录tree不包含):在第一次出现 后"─ "插入,然后在循环中用空格替换第一个之前的每个字符。/"\u2500 "/

tree --noreport | sed '
  s|'$'\u2500'' |&/|;t1
  b
  :1
    s|^\( *\)[^ /]|\1 |
  t1'

使用以下命令会更容易一些perl

tree --noreport | perl -C -pe 's{^.*?\x{2500} }{" " x length($&) . "/"}e'

答案2

这是一个bash递归输出在顶级目录中找到的名称的函数:

mytree () (
    topdir="${1-.}"
    indent="${2-0}"

    shopt -s nullglob
    shopt -s dotglob

    # output directory name
    printf "%${indent}s'%s'/\n" "" "${topdir##*/}"

    indent=$(( indent + 4 ))

    for name in "$topdir"/*; do
        if [ -h "$name" ]; then
            # output symbolic link name and target
            printf "%${indent}s'%s' --> '%s'\n" "" "${name##*/}" "$( readlink -- "$name" )"
        elif [ -d "$name" ]; then
            # recurse into directories
            mytree "$name" "$indent"
        else
            # output other type of name (not directory or symbolic link)
            printf "%${indent}s'%s'\n" "" "${name##*/}"
        fi
    done
)

该函数mytree采用一个参数(第二个参数仅在递归调用中使用),这是要处理的顶级目录。如果没有给出参数,它将使用当前目录作为列出的顶级目录。

输出如下:

'Work'/
    'Data'/
        's3wes.all.tab.frq.counts'
        's3wes.con.tab.frq.counts'
        'sullivan.txt'
    'Development'/
        'ENA-submission'/
            '.git'/
                'COMMIT_EDITMSG'

ETC。

也就是说,名称用单引号引起来,并且目录将有一个尾随/.此外,符号链接将显示为,例如,

'embl-validator.jar' --> 'embl-api-validator-1.1.158.jar'

通过更改三个调用可以轻松更改输出格式printf

相关内容