私の変数を使ってテンプレートからyamlファイルを作成しようとしています。私のyamlテンプレートは次のとおりです
number: {{NUMBER}}
name: {{NAME}}
region: {{REGION}}
storenum: {{STORENUM}}
clients: {{CLIENTS}}
tags: {{TAGS}}
storename: {{STORENAME}}
employee: {{EMPLOYEE}}
products: {{PRODUCTS}}
しかし、私の変数はCSVファイルにあります。構造は変数です。
Number - Name - Region - Storenum
StoreX - StoreX - New York - 30
これで、可変パラメータを持つテンプレートから生成される小さなスクリプトが作成され、テンプレートは次のようになりますscript.sh template.yml -f variables.txt
。私の結果は次のとおりです
number: 37579922
name: Store1
region: New York
storenum: 32
clients: 100
tags: stores
storename: Store newyork
employee: 10
products: 200
しかし、一度に1つしかできません。 CSVパラメータを読み取ってプログラムに送信して、たとえばTemplate1,Template2,etc
CSVパラメータで生成する方法はありますか?
#!/bin/bash
readonly PROGNAME=$(basename $0)
config_file="<none>"
print_only="false"
silent="false"
usage="${PROGNAME} [-h] [-d] [-f] [-s] --
where:
-h, --help
Show this help text
-p, --print
Don't do anything, just print the result of the variable expansion(s)
-f, --file
Specify a file to read variables from
-s, --silent
Don't print warning messages (for example if no variables are found)
examples:
VAR1=Something VAR2=1.2.3 ${PROGNAME} test.txt
${PROGNAME} test.txt -f my-variables.txt
${PROGNAME} test.txt -f my-variables.txt > new-test.txt"
if [ $# -eq 0 ]; then
echo "$usage"
exit 1
fi
if [[ ! -f "${1}" ]]; then
echo "You need to specify a template file" >&2
echo "$usage"
exit 1
fi
template="${1}"
if [ "$#" -ne 0 ]; then
while [ "$#" -gt 0 ]
do
case "$1" in
-h|--help)
echo "$usage"
exit 0
;;
-p|--print)
print_only="true"
;;
-f|--file)
config_file="$2"
;;
-s|--silent)
silent="true"
;;
--)
break
;;
-*)
echo "Invalid option '$1'. Use --help to see the valid options" >&2
exit 1
;;
# an option argument, continue
*) ;;
esac
shift
done
fi
vars=$(grep -oE '\{\{[A-Za-z0-9_]+\}\}' "${template}" | sort | uniq | sed -e 's/^{{//' -e 's/}}$//')
if [[ -z "$vars" ]]; then
if [ "$silent" == "false" ]; then
echo "Warning: No variable was found in ${template}, syntax is {{VAR}}" >&2
fi
fi
# Load variables from file if needed
if [ "${config_file}" != "<none>" ]; then
if [[ ! -f "${config_file}" ]]; then
echo "The file ${config_file} does not exists" >&2
echo "$usage"
exit 1
fi
source "${config_file}"
fi
var_value() {
eval echo \$$1
}
replaces=""
# Reads default values defined as {{VAR=value}} and delete those lines
# There are evaluated, so you can do {{PATH=$HOME}} or {{PATH=`pwd`}}
# You can even reference variables defined in the template before
defaults=$(grep -oE '^\{\{[A-Za-z0-9_]+=.+\}\}' "${template}" | sed -e 's/^{{//' -e 's/}}$//')
for default in $defaults; do
var=$(echo "$default" | grep -oE "^[A-Za-z0-9_]+")
current=`var_value $var`
# Replace only if var is not set
if [[ -z "$current" ]]; then
eval $default
fi
# remove define line
replaces="-e '/^{{$var=/d' $replaces"
vars="$vars
$current"
done
vars=$(echo $vars | sort | uniq)
if [[ "$print_only" == "true" ]]; then
for var in $vars; do
value=`var_value $var`
echo "$var = $value"
done
exit 0
fi
# Replace all {{VAR}} by $VAR value
for var in $vars; do
value=$(var_value $var | sed -e "s;\&;\\\&;g" -e "s;\ ;\\\ ;g") # '&' and <space> is escaped
if [[ -z "$value" ]]; then
if [ $silent == "false" ]; then
echo "Warning: $var is not defined and no default is set, replacing by empty" >&2
fi
fi
# Escape slashes
value=$(echo "$value" | sed 's/\//\\\//g');
replaces="-e 's/{{$var}}/${value}/g' $replaces"
done
escaped_template_path=$(echo $template | sed 's/ /\\ /g')
eval sed $replaces "$escaped_template_path"
ベストアンサー1
次のコマンドを使用してPerlでこれを行う非常に簡単な例があります。テキスト::CSVCSVを解析するモジュールです。
コマンドラインオプションの処理は行われません(ただし、以下を使用して簡単に実行できます)。GetSelect::標準または、Getopt::Longであれば十分ですが、基本的(Perlには含まれています)または次のような高度なモジュールです。Getopt::目覚める、インストールが必要ですが、オプションを使用して必要なほとんどすべての操作を実行できます。
これは、単にテンプレートを区切り文書としてスクリプトに含めることです。より複雑なテンプレートが必要な場合は、次を使用してください。テキスト::テンプレートライブラリモジュール。
また、出力を標準出力として印刷します。通常どおりシェルからリダイレクトできます。あるいは、各csv入力行の出力を別々のファイルに保存する必要がある場合は、Perlがファイルを簡単に書き込むためにファイルを開き、出力を文書に印刷することもできます。
約140行(そのうちの1/3はコメント、空白行、使用法メッセージ)のbashスクリプトと比較すると、このPerlスクリプトには合計35行があり、そのうち12行はテンプレート、6行はコメント、8行は中に空白行があります。 Bashのコード約90行と比較すると、実際のコードは9行です。
Bashスクリプトとは異なり、引用や空白の問題がなく、ビルドされたsed
(grep、sedと同じ)、trなどの外部プログラムを繰り返し分岐する必要がないため、より速く実行されます。 -Perlの場合)。また、Text::CSV モジュールは、カンマを含むフィールド (TAGS フィールド) を簡単に処理できます。これは正規表現に偽造するのではなく、実際のCSVパーサーを使用する利点の1つです。
#!/usr/bin/perl
use strict;
use Text::CSV;
# open the CSV file for read
my $file = 'data.csv';
open(my $fh, "<", $file) or die "Couldn't open $file: $!\n";
# initialise a csv object
my $csv = Text::CSV->new();
# read the header line
my @headers = $csv->getline($fh);
$csv->column_names(@headers);
# iterate over each line of the CSV file, reading
# each line into a hash (associative array) reference.
while (my $row = $csv->getline_hr($fh)) {
print <<__EOF__;
number: $row->{NUMBER}
name: $row->{NAME}
region: $row->{REGION}
storenum: $row->{STORENUM}
clients: $row->{CLIENTS}
tags: $row->{TAGS}
storename: $row->{STORENAME}
employee: $row->{EMPLOYEE}
products: $row->{PRODUCTS}
__EOF__
}
close($fh);
data.csv
以下が含まれている場合:
NUMBER,NAME,REGION,STORENUM,CLIENTS,TAGS,STORENAME,EMPLOYEE,PRODUCTS
37579922,Store1,New York,32,100,stores,Store newyork,10,200
2,Store2,Somewhere,2,100,"tag1,tag2,tag3",Somewhere Store,5,10
3,Store3,Elsewhere,3,100,"tag1,tag3",Elsewhere Store,3,100
次に実行すると、次のような出力が生成されます。
$ ./template-example.pl
number: 37579922
name: Store1
region: New York
storenum: 32
clients: 100
tags: stores
storename: Store newyork
employee: 10
products: 200
number: 2
name: Store2
region: Somewhere
storenum: 2
clients: 100
tags: tag1,tag2,tag3
storename: Somewhere Store
employee: 5
products: 10
number: 3
name: Store3
region: Elsewhere
storenum: 3
clients: 100
tags: tag1,tag3
storename: Elsewhere Store
employee: 3
products: 100
ちなみに、python
Pythonで書くのはPerlで書くのと同じくらい簡単です。