Простой и стандартный способ создания файлов на основе шаблонов?

В вашем коде нет переменной списка. У вас есть строка.

Вызов test1использует расширение $letterListбез кавычек. Это заставит оболочку разделить свое значение на несколько слов по пробелам, табуляциям и символам новой строки (по умолчанию ), и каждое слово будет подвергаться подстановке имени файла (, если оно содержит символы подстановки имени файла ). Результирующие слова передаются в test1как отдельные аргументы.

В test1вы помещаете только самый первый из этих аргументов в letterList.

Если вы хотите передать строку из $letterListкак есть в test1из test2, вам нужно заключить ее расширение в двойные кавычки в вызове:

test1 "$letterList"

Между прочим, вы полагаетесь на то, что оболочка выполняет разбиение $letterListзначения в вашем цикле вtest1(той же механике, которая вызывает вашу проблему ), но вы никогда не защищаете код от случайное выполнение подстановки имени файла (проверьте свой скрипт, например, test2 "A B C *"чтобы понять, что я имею в виду ).


Если вы хотите передать список , а не одну строку, вызовите test2со списком, а не со строкой:

test2 A B C "Hello World" "* *"

Затем в test2передайте аргументы вtest1:

#!/bin/sh

test1 "$@"

Здесь "$@"расширит список позиционных параметров (до аргументов скрипта ), при этом каждый отдельный параметр будет заключен в кавычки.Это означает, что такой аргумент, как Hello World, не будет разделен на несколько аргументов при вызове test1, и строка * *также не будет разделена на две части, и не произойдет подстановки имен файлов.

В test1перебрать аргументы:

#!/bin/sh

for arg in "$@"; do
    printf '%s\n' "$arg"
done

или

#!/bin/sh

for arg do
    printf '%s\n' "$arg"
done

... или, если вы просто хотите напечатать аргументы, просто

#!/bin/sh

printf '%s\n' "$@"

Я везде использовал /bin/shв качестве оболочки, так как здесь нет ничего специфичного для bash.

1
27.09.2020, 15:05
1 ответ

На самом деле очень легко написать что-то подобное. Например, вы можете получить файл с парами key=value, а затем использовать его для замены содержимого шаблона. Например:

$ cat template
Hello $name,
someone told me you really like $thing!

$ cat values
name=Bob
thing=chocolate

Тогда ваш сценарий будет:

#!/bin/sh

## source the key/value pairs
. "$1"

## Replace them in the template
sed -e "s/\\\$name/$name/g" -e "s/\\\$thing/$thing/g" "$2"

И вы запускаете это так:

$ foo.sh /full/path/to/values template
Hello Bob,
someone told me you really like chocolate!

Конечно, это требует, чтобы вы знали имена ключей заранее. Альтернативой может быть:

#!/bin/sh

tmpFile=$(mktemp)
cp -- "$2" "$tmpFile"

while IFS='=' read -r key value; do
  sed -i -e "s/\$$key/$value/g" "$tmpFile"
done < "$1"

cat "$tmpFile"

Другим вариантом может быть использование evalдля раскрытия переменных. Однако это опасно, поскольку открывает возможность внедрения кода, если значения в файле могут быть опасными. Если это не проблема для вас, попробуйте:

#!/bin/sh

## source the key/value pairs
. "$1"

## load the contents of the template
template="$(cat "$2")"
## Now print, but expanding the variables. We need to 
## unset IFS to protect the newlines.
IFS=
eval echo \"$template\"
0
18.03.2021, 23:02

Теги

Похожие вопросы