Bash:在第一次出现字母字符后拆分变量

Bash:在第一次出现字母字符后拆分变量

我有一个变量,其中包含 crontab 中的一行

例如:

0 22 * * 1-5 echo hello

我想将其分为 2 个变量,一个变量用数字或星号表示作业的周期,另一个变量用作业运行时要执行的命令。

所以我需要找到一种方法在第一次出现字母字符时分割字符串,但我不知道如何做到这一点。

答案1

这并不完全是您正在寻找的,但应该适合您的用例。将该行读入六个变量,并按变量定义的空格和制表符分隔IFS

修改后的 crontab 条目的示例:

$ line='0   22  * * 1-5 echo "foo  bar   baz"'
$ IFS=$'\t ' read -r a b c d e cmd <<<"$line"
$ echo "$a $b $c $d $e"
0 22 * * 1-5
$ echo "$cmd"
echo "foo  bar   baz"

请注意,前五个字段中的多个空格(或制表符)被压缩为一个空格字符,但命令中的空格/制表符保持不变。"$a $b $c $d $e"如果需要,您可以分配给单个变量。

答案2

这可以通过以下方式完成外壳参数扩展模式匹配

$ line='0 22 * * 1-5 echo hello'
$ prefix=${line%%[[:alpha:]]*}     #(a)
$ echo "$prefix"
0 22 * * 1-5 
$ suffix=${line#"$prefix"} .       #(b)
$ echo "$suffix"
echo hello

a:从末尾开始,找到与 alpha 后跟任意字符匹配的最长子字符串,并将其从 $line 中删除

b:从头开始,从 $line 中删除前缀 test。

答案3

我认为您可以使用 来执行此操作awk,特别是因为您的标签表明您想在 shell 脚本中使用它。看一下下面的代码片段,我将像其他回复者一样,为参数分配一个 bash 变量,其中包含您可能处理的内容:

#!/bin/bash

# fill 'line' with example content
line='0   22  * * 1-5 echo foo  bar   baz -o outfile.txt *'

# split 'line' into "scheduling" and "command" part:
SCHED=$(awk '{match($0, "^([0-9* -]*)([[:print:]]*)", a); print a[1]}' <<< "$line")
echo "$SCHED"
CMD=$(awk '{match($0, "^([0-9* -]*)([[:print:]]*)", a); print a[2]}' <<< "$line")
echo  "$CMD"

如果你测试这个,它应该输出

user@host $ ./split_test.sh 
0   22  * * 1-5 
echo foo  bar   baz -o outfile.txt *

解释

  • 在执行实际“拆分”的两行中,我将左侧的变量分配为该$( ... )部分中命令的输出(参见例如高级 Bash 脚本编写指南例如),其中我输入变量的内容,通过双括号( ')$line防止通配符(这样,除其他外,空白被“按原样”保留)。" ... "awk
  • awk调用使用内部match()函数来查找字符串中的特定模式,在我们的例子中,( ... )行开头的一组包含数字、星号、空格和破折号的任意组合,数量不限,后跟一组包含任何可打印字符,数量也不受限制。由于正则表达式是贪婪的,因此两个部分都将通过最长的可能子字符串进行匹配,因此第 1 组实际上会继续下去,直到./找到第一个不适合其中的字符(即第一个字母数字字符,甚至 )。第二组只是该行的剩余部分,并且可以包含所有可打印字符,包括数字和特殊字符。
  • 使用awksmatch函数背后的想法是,如果您通过将子组括在括号中来指定子组,则可以指示awk将模式的实际值填充到数组中,在本例中a,这样a[1]包含 的实际值组 1(“调度”部分)和a[2]组 2(“命令”部分)的实际值。
  • 虽然有点不优雅,但我们应用了两次,awk在第一次调用中输出第一部分,在第二次调用中输出第二部分,以将值分配给单独的 bash 变量。

如果你想了解更多这方面的知识,你可以看看GNU Awk 用户指南

答案4

您可以使用 cut 来分隔由空格分隔的值,如下所示:

#/bin/sh

var='0 22 * * 1-5 echo hello'

first=$(echo -n "$var" | cut -d' ' -f1)
second=$(echo -n "$var" | cut -d' ' -f2)
third=$(echo -n "$var" | cut -d' ' -f3)
fourth=$(echo -n "$var" | cut -d' ' -f4)
fifth=$(echo -n "$var" | cut -d' ' -f5)

restofvar=$(echo -n "$var" | cut -d' ' -f6,7)

E:正如评论中指出的,如果字符串中有多个空格,则必须将它们替换为单个空格:

var=$(echo "$var" | tr -s " ")

相关内容