【问题标题】:Strip directory from filename in checksum output从校验和输出中的文件名中去除目录
【发布时间】:2021-10-19 06:20:06
【问题描述】:

我有一个在 unix shell 脚本中使用的校验和的输出,我只需要显示校验和值和文件名。

$ Cksum path/path2/f1.txt | awk '{print $1,$2}'
1237668 path/path2/f1.txt 

但是我想要没有目录的文件名:

1237668 f1.txt 

我试过 sed,我只得到文件名而不是校验和:

$ Cksum path/path2/f1.txt | sed 's/.*path2//'
/f1.txt

【问题讨论】:

  • 您需要将$2 替换为$3,因为$2 包含文件大小,而不是文件名。

标签: shell unix awk sed


【解决方案1】:

假设您的文件名不包含空格,这里是sedawk 解决方案:

更简单的sed

cksum path/to/f.txt | sed 's/ .*[/ ]/ /'

878395353 f.txt

这个sed 从空格字符开始匹配并匹配到最后一个/ 或空格,因为.* 是贪婪的。我们只是用一个空格替换这个匹配的文本。


或使用/ 或空格作为输入字段分隔符的更简单的awk

cksum path/to/f.txt | awk -F '[ /]' '{print $1, $NF}'

878395353 f.txt

【讨论】:

  • 顺便说一句;使用 sed 和替换命令,通常使用的分隔符是正斜杠 /,但如果它使正则表达式/替换更容易(因为您选择了 ~),则可以将其更改为另一个字符。但是,在这种情况下,由于 / 在括号表达式内,因此无需更改分隔符,因此 sed 's/ .*[/ ]/ /' file 也可以使用,也许更容易看?
  • 谢谢。我确实用过这个。校验和路径1/路径2/文件名.txt | awk 'BEGIN{FS="/";} { print $1, $NF} 我现在得到校验和值大小文件名.txt。我想摆脱尺寸,但无法。
  • 我使用了 cksum path/path2/f1.txt | awk '开始 {打印 $1,$NF}| awk 'print$1, $3}' 并获得所需的输出..works
  • 您实际上不需要使用 2 awk。它可以在一个 awk 中完成
【解决方案2】:

假设/ 字符只出现在#2 字段中,删除字段#2 之后的所有内容;然后删除目录名称:

 Cksum path/path2/f1.txt | 
 sed 's# [^/]*$##;s# .*/# #'

【讨论】:

    【解决方案3】:

    基于man cksum

    cksum 实用程序将三个空格写入标准输出 每个输入文件的分隔字段。这些字段是校验和 CRC,文件中的八位字节总数和文件名。

    使用sed,您可以使用 3 个捕获组并在替换中使用组 1 和 3。

    ([^[:space:]]+) [^[:space:]]+ (.*/)?([^[:space:]]+)
    

    说明

    • ([^[:space:]]+) 第 1 组,匹配 1+ 个非空白字符
    • [^[:space:]]+ 匹配 1+ 个字符而不是空格之间的空白字符
    • (.*/)? 可选匹配组 2 匹配直到最后一次出现 /
    • ([^[:space:]]+) 第 3 组,匹配 1+ 个非空白字符

    例如:

    cksum ./file.txt # --> 3777026118 8 ./file.txt
    

    使用sed

    cksum ./file.txt | sed -E 's~([^[:space:]]+) [^[:space:]]+ (.*/)?([^[:space:]]+)~\1 \3~' 
    

    输出

    3777026118 file.txt
    

    使用awk打印第3个字段拆分结果中的第一个字段和最后一项:

    cksum ./file.txt | awk '
    {
      n=split($3,a,"/")
      print $1, a[n]
    }'
    

    输出

    3777026118 file.txt
    

    【讨论】:

    • Perl 扩展 \S 可能在 sed 中不可用,即使使用 -E。无论如何,假设您没有包含空格的文件名(这个答案似乎已经假设),只需 's%[^[:space:]]+/%%' 应该可以移植。
    • @tripleee 我明白了,感谢您指出这一点。我在我的 Mac 上对此进行了测试,但它不适用于 \S。现在它可以在 Ubuntu 和 Mac 上使用 [^[:space:]]+
    • 对我来说还是有点复杂,但感谢修复。 /g 仍然是多余的;您不希望(也不可能)每行有多个匹配项。
    【解决方案4】:

    注意:我不知道您使用的Cksum 命令。我的cksum 输出 3 个字段:校验和、大小和文件名。如果您的行为不同,请调整以下索引。

    如果你的 shell 是bash,你可以使用bash 数组和basename。如果文件名中没有空格:

    $ a=($(cksum path/path2/f1.txt))
    $ printf '%s %s\n' "${a[0]}" "$(basename ${a[2]})"
    857691210 f1.txt
    

    如果文件名中有空格,请调整 printf 参数:

    $ a=($(cksum "path/path2/f 1.txt"))
    $ printf '%s %s\n' "${a[0]}" "$(basename "${a[*]:2}")"
    857691210 f 1.txt
    

    如果您更喜欢引用文件名:

    $ printf '%s "%s"\n' "${a[0]}" "$(basename "${a[*]:2}")"
    857691210 "f 1.txt"
    

    【讨论】:

    • 我没有测试这个,但是a[0]a[2],没有a[1]
    • OP 显然只想要校验和和文件的基本名称,而不是大小。
    • 哦,尺寸,我忘了。所以你说原来的问题应该包含$3而不是$2awk '{print $1, $3}'?
    • 是的,可能。除非这个Cksum(大写C)OP 的使用与我的cksum 不同...
    【解决方案5】:

    你也可以使用:

    cd $(dirname path/path2/f1.txt); cksum $(basename path/path2/f1.txt)
    

    或者,保持当前目录不变:

    a=$(pwd); cd $(dirname path/path2/f1.txt); cksum $(basename path/path2/f1.txt); cd $a
    

    【讨论】:

      【解决方案6】:

      Awk 可以做到这一点。例如:

      awk '{ printf("%d", $1); n=split($2,a,"/"); print(" ", a[n])}'

      测试:

      echo "1237668 path/path2/f1.txt"  | awk  '{ printf("%d", $1); n=split($2,a,"/"); print(" ", a[n])}'
      
      1237668  f1.txt
      

      第一个元素只是 printf 中带有 $1 的打印。 第二个是在 / 上拆分,然后打印最后一个元素:

      How to split a delimited string into an array in awk?

      how to access last index of array from split function inside awk?

      【讨论】:

        猜你喜欢
        • 2017-12-02
        • 2018-06-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-03-07
        • 1970-01-01
        • 2016-02-22
        相关资源
        最近更新 更多