代码之家  ›  专栏  ›  技术社区  ›  Greg

如何在bash中修剪字符串变量

  •  0
  • Greg  · 技术社区  · 4 年前

    我有一些字符串,它们最初包含不同的目录路径,其中第二个子目录和最后一个子目录的长度可能不同,如下所示

     /home/Leo/Work/CMI/ARCH/MWS/Disks
     /home/Cleo/Work/CMI/ARCH/BK/Disks
    

    我想修剪前5个子目录,只显示最后2个子目录,就像这样

     echo "/MWS/Disks"
     echo "/BK/Disks"
    

    从初始字符串中修剪前5个子目录的一种方法可能是左移每个字符,直到两个字符串都以倒数第二个“/”开头。

    这个 Bash Beginners Guide 描述了 shift built-in 向左移动命令中的位置参数并丢弃未使用的参数。但这是否可以用于从上述字符串中修剪前5个子目录,目前还不清楚。

    在Bash中,如何减少这些字符串,最好不使用循环?


    澄清

    从评论中判断,需要更多的上下文。我的Bash脚本从8英寸软盘映像中恢复历史Mdos和Qdos文件,并将文件保存到硬盘驱动器上的目录中。

    无论好坏,我创建了一个定制方案,使用3个字符的变量名存储目录路径,其中每个名称都是当前目录路径部分的首字母缩写。

    例如 MWC 是的缩写 $MY/Work/CMI 在以下路径中

    MY="$USER"
    MWC="C:/cygwin64/home/$MY/Work/CMI"
    cd "$MWC"
    pwd
    C:/cygwin64/home/$MY/Work/CMI
    

    类似地,3个字符的变量指向树的下一个子目录

    WCA="$MWC/ARCH"
    

    即 C:/cygwin64/home/$MY/Work/CMI/ARCH ,指向档案所有者库的路径。

    随着目录路径的加长,3个字符的变量可以通过在列表中保留空白来轻松识别路径。然而,每当我的脚本引用一条路径时,就会出现完整的路径。因此,需要修剪字符串中最终用户不感兴趣的部分。

    2 回复  |  直到 4 年前
        1
  •  8
  •   choroba    3 年前

    如果子目录的数量始终相同,则可以使用参数展开来删除前5个子目录:

    s=/home/Leo/Work/CMI/ARCH/MWS/Disks
    s=/${s#/*/*/*/*/*/}
    echo $s  # /MWS/Disks
    

    或者,如果你知道你需要最后两个部分,无论路径的深度是多少:

    s=/home/Leo/Work/CMI/ARCH/MWS/Disks
    last=/${s##*/}
    last_but1=${s%$last}
    last_but1=/${last_but1##*/}
    echo $last_but1$last  # /MWS/Disks
    
    • ${s#PATTERN} 删除的开头的PATTERN $s .
    • ${s%PATTERN} 从的末尾删除图案 s .
    • 具有 # 或 % ,找到PATTERN的最短匹配。将它们加倍可以使比赛尽可能长。
        2
  •  2
  •   M. Nejat Aydin    4 年前

    作为参数展开的替代方案,可以使用 =~ 操作人员

    dir='/home/Leo/Work/CMI/ARCH/MWS/Disks'
    [[ $dir =~ /[^/]*/[^/]*$ ]] && echo "${BASH_REMATCH[0]}"
    
        3
  •  0
  •   markp-fuso    4 年前

    假设输入来自一个文件(或来自另一个操作系统进程的流式传输/管道传输)。。。

    样本输入:

    $ cat dir.file
     /home/Leo/Work/CMI/ARCH/MWS/Disks
     /home/Cleo/Work/CMI/ARCH/BK/Disks
    

    一 awk 主意

    awk 'BEGIN {FS=OFS="/"} {print OFS $(NF-1),$(NF)}' dir.file
    

    这会产生:

    /MWS/Disks
    /BK/Disks
    

    如果结果需要存储以备将来使用,则根据需要添加一些代码应该不会太难(例如,重定向到文件、管道到另一个进程、作为输入传递到 while/read 循环、加载到数组等)。

    如果OP一次处理一个字符串(例如,作为循环中的变量),我可能会坚持使用参数替换解决方案(请参阅choroba的回答),该解决方案不需要任何开销来生成子流程。

        4
  •  0
  •   dan    4 年前

    Cygwin已经 find 正确的

    所以你能做到:

    cd 'C:/cygwin64/' # I guess?
    
    find "/home/$USER/work/CMI/ARCH" -mindepth 2 -maxdepth 2 -type d -name Disks |
    sed 's=/Disks$=='
    

    或者这样,列出所有这些:

    find /home/*/work/CMI/ARCH/*/ -type d -name Disks |
    sed 's=/Disks$=='
    

    如果您只想编辑字符串,可以使用前缀删除:

    $ path=/home/Leo/Work/CMI/ARCH/MWS/Disks
    $ path=/${path#/*/*/*/*/*/*}
    $ echo "$path"
    /MWS/Disks
    
    推荐文章