我可以更改 sed 的剪切命令吗?
Can I change a cut command for a sed?
我正在编写一个脚本,其中一部分是将日期值格式化为与 SQL*Plus 8 兼容的日期值。
日期格式为:
20191115103845
我需要将此字符串更改为
to_date('2019/11/15:10:38:45', 'yyyy/mm/dd:hh24:mi:ss')
我用的是剪切工具:
funcion(){
data=
year=$(echo $data| cut -c1,2,3,4)
month=$(echo $data | cut -c5,6)
day=$(echo $data | cut -c7,8)
hour=$(echo $data| cut -c9,10)
min=$(echo $data| cut -c11,12)
sec=$(echo $date | cut -c13,14)
echo "to_date('"$year"/"$month"/"$day":"$hour":"$min":"$sec"', 'yyyy/mm/dd:hh24:mi:ss')"
}
funcion $data_to_format
(data_to_format=20191115103845)
我的问题是这需要几秒钟的时间,我打算将此脚本用于超过 100 个文件,每个文件都有 100 多个日期。所以我认为 'sed' 命令可能对此更好。
但是我使用 ksh88(旧 ksh)并且 sed 没有 -E 选项并且无法使其工作。
谁能帮我解决旧的正则表达式 sed 解决方案?
您能否尝试在 GNU awk
.
中使用显示的示例进行跟踪、编写和测试
awk -v s1="7" -v firstPart="to_date(" -v lastPart="yyyy/mm/dd:hh24:mi:ss" '
{
print firstPart s1 substr([=10=],1,4) "/" substr([=10=],5,2) "/" substr([=10=],7,2)":"\
substr([=10=],9,2)":"substr([=10=],11,2)":"substr([=10=],13,2) s1 ", " s1\
lastPart s1 ")"
}
' Input_file
解释:
-v s1="7"
: 创建名为 s1
的变量,其中的值为 '
。
-v firstPart="to_date("
: 创建变量 firstPart
其中包含字符串 to_date(
。
-v lastPart="yyyy/mm/dd:hh24:mi:ss"
: 创建其中包含字符串 yyyy/mm/dd:hh24:mi:ss
的变量 lastPart。
print
: 使用打印函数打印变量和值。
firstPart s1 substr([=23=],1,4) "/" substr([=23=],5,2) "/" substr([=23=],7,2)":"\ substr([=23=],9,2)":"substr([=23=],11,2)":"substr([=23=],13,2) s1 ", " s1\ lastPart s1 ")"
:根据 OP 的要求在此处打印变量和子字符串。
第二个解决方案:这里也添加一个sed
解决方案,这里使用sed
的反向引用能力.
echo "20191115103845" |
sed 's/\(....\)\(..\)\(..\)\(..\)\(..\)\(..\)/to_date(\x27\/\/:::\x27, \x27yyyy\/mm\/dd:hh24:mi:ss\x27)/'
OR 感谢 tripleee 因为 \x27
可能在少数 sed 中不受支持所以添加另一种使用 [= 的方式16=] 里面 sed
代码。
echo "20191115103845" |
sed 's/\(....\)\(..\)\(..\)\(..\)\(..\)\(..\)/to_date('"'"'\/\/:::'"'"', '"'"'yyyy\/mm\/dd:hh24:mi:ss'"'"')/'
可能更好的方法是一直使用 shell 内置参数扩展。
没有一种简单的方法可以一步完成,但是您可以一次删除一个前缀,然后处理剩余的尾部。简而言之,${variable#pattern}
returns $variable
删除了 pattern
上的任何前缀匹配,并且 ${variable%pattern}
对后缀匹配进行了相同的操作。
funcion(){
data=${1#[0-9][0-9][0-9][0-9]}
year=${1%"$data"}
data=${data#"$year"}
tail=${data#[0-9][0-9]}
month=${data%"$tail"}
data=${data#"$month"}
tail=${data#[0-9][0-9]}
day=${data%"$tail"}
data=${data#"$day"}
tail=${data#[0-9][0-9]}
hour=${data%"$tail"}
data=${data#"$hour"}
tail=${data#[0-9][0-9]}
min=${data%"$tail"}
sec=${tail#"$min"}
echo "to_date('"$year"/"$month"/"$day":"$hour":"$min":"$sec"', 'yyyy/mm/dd:hh24:mi:ss')"
}
这看起来很麻烦,但您应该会发现它比调用外部子进程(更不用说 6 个,就像在您的原始示例中那样)更快。
为了提高效率,如果您只是转换字符串,我不会为此使用任何外部工具,只需更改 shell 并使用 bash:
$ cat tst.sh
#!/usr/bin/env bash
funcion() {
local date=
if [[ "$date" =~ ^(....)(..)(..)(..)(..)(..)$ ]]; then
printf "todate('%s/%s/%s:%s:%s:%s', 'yyyy/mm/dd/hh24:mi:ss')\n" \
"${BASH_REMATCH[1]}" \
"${BASH_REMATCH[2]}" \
"${BASH_REMATCH[3]}" \
"${BASH_REMATCH[4]}" \
"${BASH_REMATCH[5]}" \
"${BASH_REMATCH[6]}"
fi
}
funcion '20191115103845'
$ ./tst.sh
todate('2019/11/15:10:38:45', 'yyyy/mm/dd/hh24:mi:ss')
如果您在循环中执行此操作,则将整个 shell 循环替换为对 awk 的一次调用。
我正在编写一个脚本,其中一部分是将日期值格式化为与 SQL*Plus 8 兼容的日期值。 日期格式为:
20191115103845
我需要将此字符串更改为
to_date('2019/11/15:10:38:45', 'yyyy/mm/dd:hh24:mi:ss')
我用的是剪切工具:
funcion(){
data=
year=$(echo $data| cut -c1,2,3,4)
month=$(echo $data | cut -c5,6)
day=$(echo $data | cut -c7,8)
hour=$(echo $data| cut -c9,10)
min=$(echo $data| cut -c11,12)
sec=$(echo $date | cut -c13,14)
echo "to_date('"$year"/"$month"/"$day":"$hour":"$min":"$sec"', 'yyyy/mm/dd:hh24:mi:ss')"
}
funcion $data_to_format
(data_to_format=20191115103845)
我的问题是这需要几秒钟的时间,我打算将此脚本用于超过 100 个文件,每个文件都有 100 多个日期。所以我认为 'sed' 命令可能对此更好。 但是我使用 ksh88(旧 ksh)并且 sed 没有 -E 选项并且无法使其工作。
谁能帮我解决旧的正则表达式 sed 解决方案?
您能否尝试在 GNU awk
.
awk -v s1="7" -v firstPart="to_date(" -v lastPart="yyyy/mm/dd:hh24:mi:ss" '
{
print firstPart s1 substr([=10=],1,4) "/" substr([=10=],5,2) "/" substr([=10=],7,2)":"\
substr([=10=],9,2)":"substr([=10=],11,2)":"substr([=10=],13,2) s1 ", " s1\
lastPart s1 ")"
}
' Input_file
解释:
-v s1="7"
: 创建名为s1
的变量,其中的值为'
。-v firstPart="to_date("
: 创建变量firstPart
其中包含字符串to_date(
。-v lastPart="yyyy/mm/dd:hh24:mi:ss"
: 创建其中包含字符串yyyy/mm/dd:hh24:mi:ss
的变量 lastPart。print
: 使用打印函数打印变量和值。firstPart s1 substr([=23=],1,4) "/" substr([=23=],5,2) "/" substr([=23=],7,2)":"\ substr([=23=],9,2)":"substr([=23=],11,2)":"substr([=23=],13,2) s1 ", " s1\ lastPart s1 ")"
:根据 OP 的要求在此处打印变量和子字符串。
第二个解决方案:这里也添加一个sed
解决方案,这里使用sed
的反向引用能力.
echo "20191115103845" |
sed 's/\(....\)\(..\)\(..\)\(..\)\(..\)\(..\)/to_date(\x27\/\/:::\x27, \x27yyyy\/mm\/dd:hh24:mi:ss\x27)/'
OR 感谢 tripleee 因为 \x27
可能在少数 sed 中不受支持所以添加另一种使用 [= 的方式16=] 里面 sed
代码。
echo "20191115103845" |
sed 's/\(....\)\(..\)\(..\)\(..\)\(..\)\(..\)/to_date('"'"'\/\/:::'"'"', '"'"'yyyy\/mm\/dd:hh24:mi:ss'"'"')/'
可能更好的方法是一直使用 shell 内置参数扩展。
没有一种简单的方法可以一步完成,但是您可以一次删除一个前缀,然后处理剩余的尾部。简而言之,${variable#pattern}
returns $variable
删除了 pattern
上的任何前缀匹配,并且 ${variable%pattern}
对后缀匹配进行了相同的操作。
funcion(){
data=${1#[0-9][0-9][0-9][0-9]}
year=${1%"$data"}
data=${data#"$year"}
tail=${data#[0-9][0-9]}
month=${data%"$tail"}
data=${data#"$month"}
tail=${data#[0-9][0-9]}
day=${data%"$tail"}
data=${data#"$day"}
tail=${data#[0-9][0-9]}
hour=${data%"$tail"}
data=${data#"$hour"}
tail=${data#[0-9][0-9]}
min=${data%"$tail"}
sec=${tail#"$min"}
echo "to_date('"$year"/"$month"/"$day":"$hour":"$min":"$sec"', 'yyyy/mm/dd:hh24:mi:ss')"
}
这看起来很麻烦,但您应该会发现它比调用外部子进程(更不用说 6 个,就像在您的原始示例中那样)更快。
为了提高效率,如果您只是转换字符串,我不会为此使用任何外部工具,只需更改 shell 并使用 bash:
$ cat tst.sh
#!/usr/bin/env bash
funcion() {
local date=
if [[ "$date" =~ ^(....)(..)(..)(..)(..)(..)$ ]]; then
printf "todate('%s/%s/%s:%s:%s:%s', 'yyyy/mm/dd/hh24:mi:ss')\n" \
"${BASH_REMATCH[1]}" \
"${BASH_REMATCH[2]}" \
"${BASH_REMATCH[3]}" \
"${BASH_REMATCH[4]}" \
"${BASH_REMATCH[5]}" \
"${BASH_REMATCH[6]}"
fi
}
funcion '20191115103845'
$ ./tst.sh
todate('2019/11/15:10:38:45', 'yyyy/mm/dd/hh24:mi:ss')
如果您在循环中执行此操作,则将整个 shell 循环替换为对 awk 的一次调用。