我有一个表示日期的字符串:
"May 5 2014"
我想知道如何提取" 5"从中。
到目前为止我尝试过的事情:
echo "May 5 2014" | sed 's/[^0-9]*\s//'
返回" 5 2014"
对不起补救问题。对bash来说是新手。
答案 0 :(得分:4)
使用cut
:
echo "May 5 2014" | cut -d' ' -f2
或awk
:
echo "May 5 2014" | awk '{print $2}'
如果你想在没有外部工具的情况下使用它,它将分为两个步骤:
s="May 5 2014"
t="${s#* }"
echo "${t% *}"
答案 1 :(得分:4)
如果您正在编写需要解析日期字符串的脚本,那么您肯定可以使用sed
等来完成它,而且确实已经有几个答案可以很好地完成这个操作。
但是,我的建议是让date
计划为您做繁重的工作:
$ date -d "May 5 2014" +%-d
5
date
程序的维护者毫无疑问花费了很多小时和几天的日期解析代码。为什么不利用这项工作而不是自己动手呢?
添加了BSD解决方案,例如for(Mac OS X)
date -j -f '%b %d %Y' 'May 5 2014' '+%d'
BSD上的需要告诉date
"传入"日期为-f format
,并以+format
格式输出。 -j
表示未设置日期。
答案 2 :(得分:4)
Bash的内置读取命令可以将输入拆分为多个变量。 '<<<<<<<告诉read从以下字符串中获取输入。
read first second remainder <<< "May 5 2014"
之后,“$ first”将为“May”,“$ second”将为“5”,“$ remaining”将为“2014”
通常的做法是使用''作为不感兴趣字段的占位符,因为shell会自动覆盖$ 。
read _ day _ <<< 'May 5 2014 utc'
答案 3 :(得分:3)
echo "May 5 2014" | sed 's/.* \([0-9]*\) .*/\1/'
另一个
echo "May 5 2014" | sed 's/[^ ]* //;s/ [^ ]*//'
另一个
echo "May 5 2014" | sed 's/\(.*\) \(.*\) \(.*\)/\2/'
使用grep
echo "May 5 2014" | grep -oP '\b\d{1,2}\b'
或perl
echo "May 5 2014" | perl -lanE 'say $F[1]'
作为好奇心
echo "May 5 2014" | xargs -n1 | head -2 | tail -1
echo "May 5 2014" | xargs -n1 | sed -n 2p
echo "May 5 2014" | xargs -n1 | egrep '^[0-9]{1,2}$'
最后,纯粹的bash解决方案,无需启动任何外部命令
aaa="May 5 2014"
[[ $aaa =~ (.*)[[:space:]](.*)[[:space:]](.*) ]] && echo ${BASH_REMATCH[2]}
或
aaa="May 5 2014"
re="(.*) (.*) (.*)"
[[ $aaa =~ $re ]] && echo ${BASH_REMATCH[2]}
因为Keith Reynolds要求一些基准,我测试了以下脚本。使用time
并不是完美的基准测试工具,但可以提供一些见解。
这是脚本:
xbench_with_read() {
let i=$1; while ((i--)); do
read _ day _ <<< 'May 5 2014'
echo $day
done
}
xbench_regex_3x_assign() {
let i=$1; while ((i--)); do
aaa="May 5 2014"
re="(.*) (.*) (.*)"
[[ $aaa =~ $re ]] && month="${BASH_REMATCH[1]}" && day="${BASH_REMATCH[2]}" && year="${BASH_REMATCH[3]}" && echo "$day"
done
}
xbench_regex_1x_assign() {
let i=$1; while ((i--)); do
aaa="May 5 2014"
re="(.*) (.*) (.*)"
[[ $aaa =~ $re ]] && day=${BASH_REMATCH[2]} && echo "$day"
done
}
xbench_var_expansion() {
let i=$1; while ((i--)); do
s="May 5 2014"
t="${s#* }"
echo "${t% *}"
done
}
xbench_ext_cut() {
let i=$1; while ((i--)); do
echo "May 5 2014" | cut -d' ' -f2
done
}
xbench_ext_grep() {
let i=$1; while ((i--)); do
echo "May 5 2014" | grep -oP '\b\d{1,2}\b'
done
}
xbench_ext_sed() {
let i=$1; while ((i--)); do
echo "May 5 2014" | sed 's/\(.*\) \(.*\) \(.*\)/\2/'
done
}
xbench_ext_xargs() {
let i=$1; while ((i--)); do
echo "May 5 2014" | xargs -n1 | sed -n 2p
done
}
title() {
echo '~ -'$___{1..20} '~' >&2
echo "Timing $1 $2 times" >&2
}
for script in $(compgen -A function | grep xbench)
do
cnt=100000
#external programs run 10x less times
[[ $script =~ _ext_ ]] && cnt=$(( $cnt / 10 ))
title $script $cnt
time $script $cnt | wc -l
done
以下是原始结果:
~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~
Timing xbench_ext_cut 10000 times
10000
real 0m37.752s
user 0m14.587s
sys 0m25.723s
~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~
Timing xbench_ext_grep 10000 times
10000
real 1m35.570s
user 0m21.778s
sys 0m34.524s
~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~
Timing xbench_ext_sed 10000 times
10000
real 0m41.628s
user 0m15.310s
sys 0m26.422s
~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~
Timing xbench_ext_xargs 10000 times
10000
real 1m42.235s
user 0m46.601s
sys 1m11.238s
~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~
Timing xbench_regex_1x_assign 100000 times
100000
real 0m11.215s
user 0m8.784s
sys 0m0.907s
~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~
Timing xbench_regex_3x_assign 100000 times
100000
real 0m14.669s
user 0m12.419s
sys 0m1.027s
~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~
Timing xbench_var_expansion 100000 times
100000
real 0m5.148s
user 0m4.658s
sys 0m0.788s
~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~ - ~
Timing xbench_with_read 100000 times
100000
real 0m27.700s
user 0m6.279s
sys 0m19.724s
按实际执行时间排序
纯bash解决方案100_000次
这里没什么惊喜 - 变量扩展只是最快的解决方案。
外部程序只有10_000次
这里有两个惊喜(至少对我而言):
grep
解决方案是sed
xargs
(好奇心解决方案)仅略慢于grep Enviromnent:
$ uname -a
Darwin marvin.local 13.1.0 Darwin Kernel Version 13.1.0: Thu Jan 16 19:40:37 PST 2014; root:xnu-2422.90.20~2/RELEASE_X86_64 x86_64
$ LC_ALL=C bash --version
GNU bash, version 4.2.45(2)-release (i386-apple-darwin13.0.0)
Copyright (C) 2011 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
答案 4 :(得分:0)
使用awk:
echo "May 5 2014" | awk '{print $2}'
答案 5 :(得分:0)
您可以使用bash substring expansion并应用偏移量(:4
)和长度(:1
)值。只需在字符串格式发生变化的情况下调整偏移量和长度值。
以下是一个例子:
$ date_format="May 5 2014"
$ echo "${date_format:4:1}"
5
$ date_format="2014 May 5"
$ echo "${date_format: -1:1}" # <- Watch that space before the negative value
5
$ date_format="5 May 2014"
$ echo "${date_format:0:1}"
5