【问题标题】:bash parse filenamebash 解析文件名
【发布时间】:2012-05-16 11:58:19
【问题描述】:

在 bash 中有什么方法可以解析这个文件名:

$file = dos1-20120514104538.csv.3310686

进入像 $date = 2012-05-14 10:45:38$id = 3310686 这样的变量?

谢谢

【问题讨论】:

  • 我不知道该怎么做.. 我在问是否有人这样做,因为我不知道从哪里开始...
  • 您阅读过bash 手册页吗?有一整节关于变量扩展的内容应该会给你一些想法。

标签: bash parsing tokenize


【解决方案1】:

所有这些都可以通过参数扩展来完成。请在 bash 手册页中阅读。

$ file='dos1-20120514104538.csv.3310686'
$ date="${file#*-}" # Use Parameter Expansion to strip off the part before '-'
$ date="${date%%.*}" # Use PE again to strip after the first '.'
$ id="${file##*.}" # Use PE to get the id as the part after the last '.'
$ echo "$date"
20120514104538
$ echo "$id"
3310686

结合 PE,以新的格式重新组合日期。您也可以使用 GNU 日期解析日期,但这仍然需要重新排列日期以便解析。在它目前的格式中,我会这样处理它:

$ date="${date:0:4}-${date:4:2}-${date:6:2} ${date:8:2}:${date:10:2}:${date:12:2}"
$ echo "$date"
2012-05-14 10:45:38

【讨论】:

    【解决方案2】:

    使用 Bash 的正则表达式功能:

    file='dos1-20120514104538.csv.3310686'
    pattern='^[^-]+-([[:digit:]]{4})'
    for i in {1..5}
    do
        pattern+='([[:digit:]]{2})'
    done
    pattern+='\.[^.]+\.([[:digit:]]+)$'
    [[ $file =~ $pattern ]]
    read -r _ Y m d H M S id <<< "${BASH_REMATCH[@]}"
    date="$Y-$m-$d $H:$M:$S"
    echo "$date"
    echo "$id"
    

    【讨论】:

      【解决方案3】:

      提取ID:

      f='dos1-20120514104538.csv.3310686'
      echo ${f/*./}
      # 3310686
      id=${f/*./}
      

      去掉前缀,提取核心日期数字:

      noprefix=${f/*-/}
      echo ${noprefix/.csv*/}
      # 20120514104538
      ds=${noprefix/.csv*/}
      

      像这样格式化日期(仅部分完成:)

      echo $ds | sed -r 's/(.{4})(.{2})(.{2})/\1.\2.\3/'
      

      您也可以将初始变量拆分为一个数组,

      echo $f
      # dos1-20120514104538.csv.3310686
      

      在交换 - 和 .像这样:

      echo ${f//[-.]/ }
      # dos1 20120514104538 csv 3310686
      
      ar=(${f//[-.]/ })
      echo ${ar[1]}
      # 20120514104538
      
      echo ${ar[3]}
      # 3310686
      

      日期转换也可以类似地通过数组来完成:

      dp=($(echo 20120514104538  | sed -r 's/(.{2})/ \1/g'))
      echo ${dp[0]}${dp[1]}-${dp[2]}-${dp[3]} ${dp[4]}:${dp[5]}:${dp[6]}
      

      它将所有内容分成 2 个字符的组:

      echo ${dp[@]}
      # 20 12 05 14 10 45 38
      

      并在输出中将 2012 合并在一起。

      【讨论】:

      • @VictorYarema:请不要将您最喜欢的提示放在命令前面。这使得复制/粘贴它们变得更加困难,并且它们不是代码的一部分。
      • 同意。对此感到抱歉。我在其他一些问题和答案中这样做是为了更容易区分命令和输出。后来我注意到了你刚才指出的问题。之后我发现其他一些用户只是简单地写输出评论。后一种方法让它变得更好——你可以复制带有注释输出的命令并安全地运行它。我只是没时间改成那种style
      • 如果我在每个输出行的开头添加井号,您能接受吗?
      • @VictorYarema:由于在合理的情况下输出无法(从 shell)解释为新命令,因此可能发生的最糟糕的事情是反应“找不到命令:20120514104538”等.如果用户阅读代码并试图理解它,它应该是显而易见的。但是,我自己做了(在前面放了一个哈希用于语法突出显示/颜色装饰),所以我会接受这样的编辑。
      • 已修复(注释输出和引用的文件名)。谢谢我的编辑评论,结果变成了回复。谢谢你这么用心。 :)
      【解决方案4】:

      您可以先为- 标记字符串,然后再为. 标记字符串。 SO上有很多关于如何做到这一点的主题:

      1. How do I split a string on a delimiter in Bash?
      2. Bash: How to tokenize a string variable?

      20120514104538 转换为2012-05-14 10:45:38

      由于我们知道前 4 个字符是年份,接下来的 2 个字符是月份,以此类推,您首先需要将此 token 分解为子字符串,然后重新组合成一个字符串。您可以从以下答案开始:

      1. https://stackoverflow.com/a/428580/365188

      【讨论】:

      • 现在可以,我将20120514104538 转换为2012-05-14 10:45:38
      猜你喜欢
      • 2016-06-15
      • 2010-09-08
      • 1970-01-01
      • 2014-04-28
      • 2012-09-13
      • 2020-06-16
      • 2016-01-15
      • 2018-08-30
      • 2016-10-18
      相关资源
      最近更新 更多