Переименование переменных среды путем изменения префикса имени переменной

Все утилиты, допускающие редактирование файлов в -месте, делают это путем внутренней записи результата во временный файл и последующей замены исходного файла этим временным файлом после завершения операции.


Файлы можно изменить на месте, но вы сможете только перезаписать существующие данные и/или увеличить длину файла. Это можно сделать с помощью утилиты dd, например:

$ cat file.txt
hello world
abc abc 123 123

$ cat insert.txt
hello!

$ dd if=insert.txt of=file.txt bs=1 seek=6 conv=notrunc
7+0 records in
7+0 records out 
7 bytes transferred in 0.000 secs (30918 bytes/sec)

$ cat file.txt
hello hello!
bc abc 123 123

Здесь мы вставляем то, что находится в insert.txt, в file.txt, сначала просматривая 6 байтов вперед в файле (, обходя helloи пробел ), а затем изменяя его. conv=notruncпредотвращает усечение выходного файла в конце операции записи.

Если бы if=insert.txtбыло опущено, можно было бы вставить любой текст с клавиатуры. Обратите внимание, что термин «вставка» здесь неправильный. «Перезапись» может лучше описать то, что происходит (, посмотрите, как первый символ второй строки перезаписывается новой строкой в ​​концеinsert.txt).

Однако вам вряд ли захочется редактировать файл таким образом.

4
17.10.2019, 15:07
3 ответа

Использование соответствия префикса имени переменной и косвенного обращения к переменной вbash:

proj_env_repo_db_username=username
proj_env_repo_db_host=host
proj_env_repo_db_port=port

for variable in "${!proj_env_repo@}"; do
    export "TF_ENV${variable#proj_env_repo}"="${!variable}"
done

Цикл использует "${!proj_env_repo@}"для создания списка имен переменных, которые имеют префикс имени proj_env_repo. В каждой итерации $variableбудет именем одной из этих переменных.

Внутри цикла exportиспользуется для создания новой переменной среды путем удаления префикса proj_env_repoи замены его строкой TF_ENV. Значение для новой переменной окружения получается с помощью косвенной переменной ${!variable}, т. е. значения переменной, имя которой хранится в $variable.

Чтобы дополнительно сбросить исходную переменную, используйте unset "$variable"после exportдо конца цикла.

Тестовый запуск с включенной трассировкой:

$ bash -x script.sh
+ proj_env_repo_db_username=username
+ proj_env_repo_db_host=host
+ proj_env_repo_db_port=port
+ for variable in "${!proj_env_repo@}"
+ export TF_ENV_db_host=host
+ TF_ENV_db_host=host
+ for variable in "${!proj_env_repo@}"
+ export TF_ENV_db_port=port
+ TF_ENV_db_port=port
+ for variable in "${!proj_env_repo@}"
+ export TF_ENV_db_username=username
+ TF_ENV_db_username=username

Как функция, принимающая префикс старого имени в качестве первого аргумента и новый префикс в качестве второго аргумента:

rename_var () {
    # Make sure arguments are valid as variable name prefixes
    if ! [[ $1 =~ ^[a-zA-Z_][a-zA-Z_0-9]*$ ]] ||
       ! [[ $2 =~ ^[a-zA-Z_][a-zA-Z_0-9]*$ ]]
    then
        echo 'bad variable name prefix' >&2
        return 1
    fi

    eval 'for variable in "${!'"$1"'@}"; do
              export "'"$2"'${variable#'"$1"'}"="${!variable}"
          done'
}

Здесь мы прибегаем к использованию evalповерх цикла, поскольку bashне поддерживает синтаксис ${!$1@}. Функция создает соответствующий шелл-код (в виде строки )для переименования переменных в соответствии со значениями $1и$2(1-го и 2-го аргументов, переданных функции ), а затем использует evalдля выполнения этого шелл-кода.

Эту функцию можно использовать как

rename_var project_env_repo TF_ENV

... или, используя переменные,

rename_var "$old_variable_prefix" "$new_variable_prefix"

Примечание :При выполнении подобных действий (с использованием evalпользовательского ввода )вы должны проверить, что код, который вы оцениваете, действителен и соответствует вашим ожиданиям. это быть. В данном случае это означает проверку $1и $2как допустимых префиксов имен переменных.В противном случае хотя бы кавычки и }вызовут синтаксические ошибки в eval, и есть вероятность внедрения команд.


Примечание :Впервые (я думаю ), что у меня когда-либо было использованиеeval. Я бы никогда не поставил себя в положение, когда мне нужно использовать приведенный выше код, но я, очевидно, не знаю предыстории вопроса, так что это не настоящая критика вопроса (, который сам по себе интересен. ).

Похожие (на сайте Software Engineering):

8
27.01.2020, 20:47
while IFS='=' read -r name value; do
    new_name="TF_ENV${name#proj_env_repo}"
    export "$new_name=$value"
    unset "$name"
done < <( printenv | grep proj_env_repo )

Секретные ингредиенты здесь:

3
27.01.2020, 20:47
for v in `printenv | grep proj_env_repo`
do
    eval `echo "$v=\$$v" | sed -e 's/proj_env_repo/TF_ENV/'`
    unset $v
done

echoпечатает:

proj_env_repo_db_username=$proj_env_repo_db_username

sedпреобразует первый экземпляр proj_env_repoв TF_ENV.

TF_ENV_db_username=$proj_env_repo_db_username

evalоценивает этот оператор.

unsetобеспечивает удаление старой переменной.

1
27.01.2020, 20:47

Теги

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