Я хочу создать скрипт quine .sh, и вот что у меня получилось:
quine.sh
:
#!/bin/sh
q="#!/bin/sh\nq=$q;echo \$q";echo $q
Сосредоточьтесь на этой строке:
q="#!/bin/sh\nq=$q;echo \$q";echo $q
При первом появлении $q
(в \nq=$q
) я сначала хочу установить остальную часть переменной, а затем эту часть (какую-то строку setlocal enabledelayedexpansion
в пакетных файлах).Обратите внимание, что мне нужно решение для sh
, а не для bash
или чего-то еще, так как мне нужна переносимость. Кроме того, не давайте мне советов, как сделать мой код короче и т. д. Я просто хочу получить решение для проблемы, указанной выше.
решение1
Если мы обернем начальную строку в '
s вместо "
s, то $q
не будет немедленно расширена. Затем мы можем расширить ее позже с помощью eval
:
#!/bin/sh
q='#!/bin/sh\nq=$q;eval "echo \"\$q\""';eval "echo \"$q\""
К сожалению, \n
не расширяется, '
s и "
s теряются, а \"
s становится "
s.
Выход:
#!/bin/sh\nq=#!/bin/sh\nq=$q;eval "echo \"\$q\"";eval echo "$q"
Мы довольно близки, но попытка исправить побег sed
становится довольно обременительной.
Ссылка jw013 рекомендует довольно понятный подход:
- Часть 1: Определите некоторые данные (например, переменную), которые содержат вторую часть программы.
- Часть 2: Используйте данные для вывода первой части программы, а затем используйте данные для вывода второй части программы. (Здесь обработайте перенос и экранирование, необходимые для части 1.)
Вот первая грубая попытка сделать это:
#!/bin/sh
data="echo -e \"#!/bin/sh\ndata=\"\$data\"\"\\n\$data"
echo -e "#!/bin/sh\ndata=\"$data\"\n$data"
Выход:
#!/bin/sh
data="echo -e "#!/bin/sh
data="$data""
$data"
echo -e "#!/bin/sh
data="$data""
$data
Эта попытка страдает от того, \n
что всегда интерпретируется, а \
s теряется. Нам нужен какой-то способ экранировать строку данных, когда мы печатаем ее снова.
Вот улучшение, которое использует множественные вызовы echo
для того, чтобы избежать проблем с \n
s.
#!/bin/sh
data='echo "#!/bin/sh"\necho "data=$data"\necho -e "$data"'
echo "#!/bin/sh"
echo "data='$data'"
echo -e "$data"
Он страдает от одного маленького недостатка, который трудно устранить: '
в выходных данных отсутствует s (в середине echo
):
#!/bin/sh
data='echo "#!/bin/sh"\necho "data=$data"\necho -e "$data"'
echo "#!/bin/sh"
echo "data=$data"
echo -e "$data"
Это все, что у меня есть для вас. Некоторые отправные точки для выхода из проблем. Удачи!