Bash:アルファベット文字が最初に発生した後に変数を分割する

Bash:アルファベット文字が最初に発生した後に変数を分割する

crontabの1行を含む変数があります

たとえば、

0 22 * * 1-5 echo hello

2つの変数に分割したいのですが、1つの変数はジョブの期間を数字またはアスタリスクで表し、他の変数はジョブの実行時に実行するコマンドを表します。

そのため、アルファベット文字が最初に表示されるときに文字列を分割する方法を見つける必要がありますが、どうすればよいかわかりません。

答え1

これはまさにあなたが探しているものではありませんが、あなたのユースケースに適しているはずです。行を変数で定義されているように、スペースとタブで区切られた6つの変数として読み込みます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"

最初の5つのフィールドの複数のスペース(またはタブ)は単一のスペース文字に圧縮されますが、コマンドのスペース/タブは変更されません。"$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:末尾から始まり、アルファに一致する最も長い部分文字列とそれに続く任意の文字を見つけて$ lineから削除します。

b: 最初から始めて $line からプレフィックス test を削除します。

答え3

私の考えでは、を使用してこれを行うことができると思いますawk。これは、タグがシェルスクリプトで使用したいことを示すためです。以下のコードを見てください。他の回答者が好きで、パラメータに処理できる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 *

説明する

  • 実際の「分割」を実行する2行で、左側の変数を$( ... )そのセクションのコマンド出力に割り当てます(例:高度なバッシュスクリプトガイドたとえば、変数の内容を入力すると、二重$line括弧( ')を介したワイルドカードを防ぎます(スペースは「現状のまま」残ります)。" ... "awk
  • このawk呼び出しは内部match()関数を使用して文字列内の特定のパターンを検索します。私たちの場合、( ... )数字、アスタリスク、スペース、ダッシュの組み合わせを含む行の先頭のセットと印刷可能な文字を含むセットが続きます。数量は制限されません。正規表現は貪欲なので、両方の部分は可能な限り長い部分文字列に一致するため、グループ1は最初の英数字文字と一致しない最初の文字を見つける./まで実際に続きます。 2番目のグループは単に行の残りの部分であり、数字や特殊文字を含むすべての印刷可能文字を含めることができます。
  • awks関数を使用するmatch理由は、サブグループを括弧で囲んで指定するとawk、パターンの実際の値、この場合はグループ1に含まれる実際の値aで配列を埋めるように指示できることです。a[1](「a[2]グループ2(「コマンド」」セクション)とグループ2(「コマンド」セクション)の実際の値。
  • ややエレガントではありませんが、それを2回適用して最初の呼び出しでawk最初の部分を出力し、2番目の呼び出しで2番目の部分を出力して別の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 " ")

関連情報