- プログラムは、サードパーティのプログラムを使用しないでください。 base64でもcatでもない。
- プログラムはテキストをロシア語で表示する必要があります。
- プログラムはASCIIで作成する必要がありますが、単一の文字または数字を含めることはできません。
Zshには変数を展開するためのパラメーターがあります( man zshexpnからのパラメーター展開フラグ):
echo ${(#):-65}
はラテン文字「A」を表示します。 現在のロケールで動作します。 原則として、これで目的のプログラムを作成するには十分ですが、人生を大いに促進する他の知識があります。
まず、匿名関数があるため、関数の名前を作成する必要はありません(ただし、関数を
+
で呼び出すこともできます)。また、追加の
@
配列(1つではなく、1つのスコープ内の1つのみ)を取得することもできます。
第二に、zshが数値を期待する場合はいつでも、算術展開(同じ
man zshexpn
からの算術展開、
man zshexpn
算術評価セクションで詳しく説明)を使用できます。これにより、
$(())
、
$[]
、yesそしてちょうど
$
。 上記の例を含めて、
V=0x41; echo ${(#):-V+(VV)}
書くことができ
V=0x41; echo ${(#):-V+(VV)}
V=0x41; echo ${(#):-V+(VV)}
、インデックス内の値に適用されます(
$@
を使用する場合に便利です)。
3番目に、配列を使用して
${(#)}
ような手順を実行でき、配列の各要素に
(#)
適用されます。
4番目に、複数の変換を連続して適用する必要がある場合、一時変数は必要ありません。 :
(#)
およびスペースの削除)。 文字列を変換するための一時変数も必要ありません:
${:-string}
は
string
に展開され
string
、ここには変数はありません(上記で使用したオプション)。 Bash、および一般的に他のすべてのシェルは、これを行うことができません。
したがって、次のコードを取得します。
1 (){__=$# } !;___=$[__<<__];____=$[__<<___];_____=$((___<<___)) 2 _______=$((__+(__<<(__+____))+(__<<(__+____))<<(__+____))) 3 ______=$((_______+__+__<<____)) 4 \*(){(( ${@[-__]} < ______+(______-_______)+_____ )) && { <<< $@ ; <<< $(\* $[$@+____]) } } 5 +(){<<< "${${(#)@}// }"} 6 (){ 7 (){<<< "$@"} \ 8 "$(+ _______)" \ 9 "$(+ ${@[____]}-__ ${@[____]} ______ ${@[-__]}+__ ${@[____]}-___)" \ 10 "$(+ ${@[__]}+__ ${@[____]} ${@[__]}+___ ${@[____]} ${@[____]}-___ '____<<(____-__)+__')" \ 11 } $(\* $[______])
。 ここで、最初の行では値1、2、4、8で変数を宣言し、2番目では値0x0421(U + 0421はCYRILLIC CAPITAL LETTER ES)、3番目では-0x0432(CYRILLIC SMALL LETTER VE)で宣言します。 4行目では、4の増分で数値のシーケンスを生成する再帰関数; 5行目では、上記でほぼ考慮した関数で、算術式の配列をスペースなしの文字列に変換します。
6行目の匿名関数は、4行目の関数で生成された数値を7行目の配列に関連付けるために必要です。複数の行をスペースで区切って1つに結合します。 11行目では、再帰ジェネレーターが呼び出され、残りにはテキスト自体が含まれています。
問題は解決されたようです。 以下を開始します。
env -i PATH= LANG=ru_RU.UTF-8 /bin/zsh -f script.zsh *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat *: command not found: cat +: command not found: cat +: command not found: cat +: command not found: cat (anon): command not found: cat
。 ああ、ここで何かが間違っています。最初の条件に違反しています。 それはすべて$NULLCMD
について
$NULLCMD
:コマンドがなく、リダイレクトを使用する場合、この変数の値は暗黙的に置換され、デフォルトでは
cat
等しくなります。 解決策は、
cat
関数を作成することです。
cat() while { read i } { echo $i }
(はい、中括弧のない関数の定義は正しいです。ループの場合もdo
が、
do
/
done
do
)。 これは
eval
なしでは実行できないため、実行する行は
eval 'cat()while {read i} {echo $i}'
の形式である必要があります。 ここでの小さな問題は、
<<<
を使用できないため、気にすることはできず、
echo
を含む/を返す別の変数または関数ですべてを単純に書き換えることです。 最終プログラムでは、これは
@
関数です。
(){__=$# } !;___=$[__<<__];____=$[__<<___];_____=$((___<<___)) ______=$[_____<<____-___<<____+____] ________="${(#):-______+__}${(#):-______-__}${(#):-______+____}${(#):-______+_____+___+__}" @() $________ $________ _______=$((__+(__<<(__+____))+(__<<(__+____))<<(__+____))) ______=$((_______+__+__<<____)) \*(){(( ${@[-__]} < ______+(______-_______)+_____ )) && { $(@) $@ ; $(@) $(\* $[$@+____]) } } +() $(@) "${${(#)@}// }" (){ (){$(@) "$@"} \ "$(+ _______)" \ "$(+ ${@[____]}-__ ${@[____]} ______ ${@[-__]}+__ ${@[____]}-___)" \ "$(+ ${@[__]}+__ ${@[____]} ${@[__]}+___ ${@[____]} ${@[____]}-___ '____<<(____-__)+__')" } $(\* $[______])
最後から2番目のステップは、引用符を取り除くことです。 (){__=$# } !;___=$[__<<__];____=$[__<<___];_____=$((___<<___)) ______=$[_____<<____-___<<____+____] ________=${(#):-______+__}${(#):-______-__}${(#):-______+____}${(#):-______+_____+___+__} @() $________ $________ _______=$((__+(__<<(__+____))+(__<<(__+____))<<(__+____))) ______=$((_______+__+__<<____)) \*(){(( ${@[-__]} < ______+(______-_______)+_____ )) && { $(@) $@ ; $(@) $(\* $[$@+____]) } } +() $(@) "${${(#)@}// }" (){ (){$(@) $@} \ $(+ _______) \ $(+ ${@[____]}-__ ${@[____]} ______ ${@[-__]}+__ ${@[____]}-___) \ $(+ ${@[__]}+__ ${@[____]} ${@[__]}+___ ${@[____]} ${@[____]}-___ '____<<(____-__)+__') } $(\* $[______])
少し縮小しますが、何かコードが痛々しいほど明確です: (){__=$# } !;___=$[__<<__];____=$[__<<___];_____=$[___<<___] ______=$[_____<<____-___<<____+____] ________=${(#):-______+__}${(#):-______-__}${(#):-______+____}${(#):-______+_____+___+__} @()$________ $________ _______=$[__+(__<<(__+____))+(__<<(__+____))<<(__+____)] ______=$[_______+__+__<<____] \*(){((${@[-__]}<______+(______-_______)+_____))&&{`@` $@ `\* $[$@+____]` }} +()`@` "${${(#)@}// }" (){(){`@` $@} `+ _______` `+ ${@[____]}-__ ${@[____]} ______ ${@[-__]}+__ ${@[____]}-___` `+ ${@[__]}+__ ${@[____]} ${@[__]}+___ ${@[____]} ${@[____]}-___ '____<<(____-__)+__'` } `\* $[______]`
。 env -i PATH= LANG=ru_RU.UTF-8 /bin/zsh -f script.zsh
ます。
Unicodeロケールを必要としないオプション(行
eval LANG=C
がそこに収集され、このロケールでは
${(#)}
は指定された値のバイトを生成します):
(){__=$# } !;___=$[__<<__];____=$[__<<___];_____=$[___<<___] ______=$[_____<<____-___<<____+____] ________=${(#):-______+__}${(#):-______-__}${(#):-______+____}${(#):-______+_____+___+__} @()$________ $________ ^()`@` ${(#):-$@[__]}${(#):-$@[___]} ''(){(($@<(_____<<____)))&&`@` ${(#)@}||^ $[($@)>>(____+___)|(_____<<____+_____<<(___+__))] $[($@)&(__<<(____+___)-__)|(_____<<____)]} _______=$[__+(__<<(__+____))+(__<<(__+____))<<(__+____)] ______=$[_______+__+__<<____] \*(){((${@[-__]}<${@[__]}))&&{`@` $[$@[-__]] `\* $@[__] $[$@[___]+____]` }} +(){(($#))&&`@` $('' $@[__])$(+ $@[___,-__])} /()`@` "${${(#)@}// }" `() {/ $@[__] $@[-__]+____+__ $@[__]-____ $@[-___]-__} $(\* $[#________+(_____<<__)] $[#________])` \ `() {/ $@[-__] $@[__]+__ $@[-__]+___ $@[___+__]-__} $(\* '(____<<____)+_____*___' '____<<____')`=${(#):-$[_____<<(___+__)+___+__]} (){(){`@` $@} `+ _______` `+ ${@[____]}-__ ${@[____]} ______ ${@[-__]}+__ ${@[____]}-___` `+ ${@[__]}+__ ${@[____]} ${@[__]}+___ ${@[____]} ${@[____]}-___ '____<<(____-__)+__'` } `\* '______+(______-_______)+_____' ______`
。
「フォークなし」と「アンダースコアなし」という制限を追加すると、タスクはより興味深いものになります。 この場合、いくつかのトリックを覚えておく必要があります。まず、不明なコマンドを実行しようとすると、リターンコード127で終了し、変数
$?
表示されます
$?
。
&>‐
これはエラーメッセージの出力を防ぎます:関数
/()+++++++&>-
+++++++
コマンドがない限り、
?=127
/()+++++++&>-
同等
?=127
(もちろん、この変数に割り当てることができる場合)。
+++++++
。
${#?}
は3になります。
/()''&>-
使用することもできます:このオプションは常に
$?
126
提供します
$?
、ディレクトリを実行できないため(注:空の名前で関数を定義できます。これにより、このトリックを使用できなくなります)。 最後のトリック:関数
/().&>-
$?
/().&>-
割り当て
$?
1を呼び出す試みがあるため
.
引数なし、および
/(). ''&>-
/(). ''&>-
、なぜなら
.
$PATH
で空の名前のファイルを見つけようとしますが、もちろん、
$PATH
にディレクトリの代わりにファイルを追加すると、「これはディレクトリではありません」というメッセージで同じ戻りコードを取得します:
path_item/
、および
path_item/
の存在を探します最後にこの結果につながります)。
第二に、変数
$!
バックグラウンドで実行されている最後のプロセスのPIDが含まれます。 または、バックグラウンドで何も開始されなかった場合は0(最後の部分はドキュメントに記載されていません)。
第三に、私は答える記事でこのトリックを使用しましたが、まだ使用していません。単純に文字列を連結することで数値を収集できます。 これらを
${base}#${number}
の形式で収集することもできます。これにより、タスクは生成のために単純になります:
$!
0があり、
$@
には1つの要素(1)の配列があり、
$[$@+$@]#$@$!$!$!
の形式で番号を収集し
$[$@+$@]#$@$!$!$!
2#1000
または
8
を収集します。 何らかの理由で生成したくない場合は、必要な値を
$@
に割り当てる機能を備えた匿名関数が機能します。
eval LANG=C
を実行するコードの例を次に示します。
/()+++&>- //()''&>- ///().&>- () { () { / () { / () { / ${(#):-$@[${##}<<${##}]+${##}}${(#):-$@[$#]+${##}<<${#?}}${(#):-$@[${#}-${##}]-${#?}}${(#):-$@[$#]-${##}-${##}} $@[${##}] } $@[${##}] ${##}$!$! $[${##}$!$!+${##}$!] } ${(#):-$@[$#]+${?[-${##}]}-${##}}${(#):-$@[${#}-${##}]+${?[${##}]}+${##}<<${?[${##}+${##}]}}${(#):-$@[$#]+${##}<<${#?}}${(#):-$@[$#]+${##}}=${(#):-$@[$#]-${#?}} $@[${##},${#?}] } $@ $[$@[$#]+${#}-${##}]$! $[$@[$#]+${#}]$! } ${#?} $[${#?}+${#?}] $[${#?}<<(${#?}+${#?})]
Pythonのワンライナーの例を次に示します。これは、上記のテクノロジーを使用して、
echo !
を収集し
echo !
:
#!/usr/bin/env python3.4 print(''.join( ( ' ' if i == next(iter(b' ')) else '${{(#):-$[$[$@+$@]#{:b}]}}'.format(i).replace('0', '$!').replace('1', '$@') ) for i in 'echo !'.encode('utf8')))
echo !
および手動アセンブリ
eval LANG=C
:
/()+++&>- //()''&>- ///(). ''&>- () { () { / () { / () { / ${(#):-$@[${##}<<${##}]+${##}}${(#):-$@[$#]+${##}<<${#?}}${(#):-$@[${#}-${##}]-${#?}}${(#):-$@[$#]-${##}-${##}} $@[${##}] } $@[${##}] ${##}$!$! $[${##}$!$!+${##}$!] } ${(#):-$@[$#]+${?[-${##}]}-${##}}${(#):-$@[${#}-${##}]+${?[${##}]}+${##}<<${?[${##}+${##}]}}${(#):-$@[$#]+${##}<<${#?}}${(#):-$@[$#]+${##}}=${(#):-$@[$#]-${#?}} $@[${##},${#?}] } $@ $[$@[$#]+${#}-${##}]$! $[$@[$#]+${#}]$! } ${#?} $[${#?}+${#?}] $[${#?}<<(${#?}+${#?})] : () { ${(#):-$[$[$@+$@]#$@$@$!$!$@$!$@]}${(#):-$[$[$@+$@]#$@$@$!$!$!$@$@]}${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!]}${(#):-$[$[$@+$@]#$@$@$!$@$@$@$@]} ${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$!$!$!$!$@]} ${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$@$@$@$!$@]}${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$@$@$@$@$!]}${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$@$!$!$@$!]}${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$@]}${(#):-$[$[$@+$@]#$@$!$!$!$@$!$@$@]}${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$@$@$@$!$!]} ${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$@$!$!$@$@]}${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$@$@$@$@$!]}${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$@$!$@$!$!]}${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$@$@$@$@$!]}${(#):-$[$[$@+$@]#$@$@$!$@$!$!$!$!]}${(#):-$[$[$@+$@]#$@$!$@$@$@$@$!$!]}${(#):-$[$[$@+$@]#$@$!$!$!$!$@]} } ${#?}
(
:
$?
0
が含まれることを保証するために必要
$?
)
strace
を実行すると、まだ
fork
が残っていることがわかります。起動時に、
fork
が最初に作成され、次に
+++
可能な場所がソートされます。
''
同じことが起こるので、関数
/
を
///
で置き換える必要があります。これは
/
(
//
ではなく)とまったく同じ結果になりますが、
fork
はありません。