コマンドブロックを匿名関数として処理できますか?
function wrap_this {
run_something
# Decide to run block or maybe not.
run_something else
}
wrap_this {
do_something
do_somthing else
}
# Do something else
wrap_this {
do_something_else_else
do_something_else_else_else
}
(各ブロックに対して関数やファイルを生成することはわかっていますが、場合によってはこのオプションがより明確で読みやすくなります。)
while
で行い、do/done
でfunction
行います{ multiple lines }
。 BASHには匿名関数がないことを知っていますが、関数を定義するときと同じように、複数のコマンドを別の関数に渡すことはできますかwhile
?
答え1
これは私が考えることができる最も短い解決策です。
以下の機能が提供されます。
# List processing
map() { while IFS='' read -r x; do "$@" "$x"; done; }
filter() { while IFS='' read -r x; do "$@" "$x" >&2 && echo "$x"; done; }
foldr() { local f="$1"; local result="$2"; shift 2; while IFS='' read -r x; do result="$( "$f" "$@" "$x" "$result" )"; done; echo "$result"; }
foldl() { local f="$1"; local result="$2"; shift 2; while IFS='' read -r x; do result="$( "$f" "$@" "$result" "$x" )"; done; echo "$result"; }
# Helpers
re() { [[ "$2" =~ $1 ]]; }
例:
# Example helpers
toLower() { tr '[:upper:]' '[:lower:]'; }
showStructure() { [[ "$1" == "--curly" ]] && echo "{$2; $3}" || echo "($1, $2)"; }
# All lib* directories, ignoring case, using regex
ls /usr | map toLower | filter re 'lib.*'
# All block devices. (Using test, for lack of a full bash [[ … ]].)
cd /dev; ls | filter test -b
# Show difference between foldr and foldl
$ ls / | foldr showStructure '()'
(var/, (usr/, (tmp/, (sys/, (sbin/, (run/, (root/, (proc/, (opt/, (mnt/, (media/, (lost+found/, (lib64/, (lib32/, (lib@, (home/, (etc/, (dev/, (daten/, (boot/, (bin/, ())))))))))))))))))))))
$ ls / | foldr showStructure '{}' --curly
{var/; {usr/; {tmp/; {sys/; {sbin/; {run/; {root/; {proc/; {opt/; {mnt/; {media/; {lost+found/; {lib64/; {lib32/; {lib@; {home/; {etc/; {dev/; {daten/; {boot/; {bin/; {}}}}}}}}}}}}}}}}}}}}}}
(この例はもちろん使用例です。実際、このスタイルはより複雑なユースケースにのみ適しています。)
通常、次のスタイルを使用できます。
f() { something "$@" ; }; someList | map f
g() { something "$1" "$2" …; }; someCommand | filter g
⋮ ⋮ ⋮ ⋮
そうではないかなりラムダ、しかし非常に非常に近いです。追加の文字はいくつかあります。
しかし、私が知っている限り、次の便利な略語は機能しません。
λ() { [[ $@ ]]; } # fails on spaces
λ() { [[ "${@:-1}" ${@:1:-1} ]]; } # syntax error
alias λ=test # somehow ignored
残念ながらbash
、いくつかの機能は非常に実用的な感覚を持っていますが、スタイルには適していません。
答え2
ハッキングで目的の操作を正常に実行しましたeval
。警告しますevalは安全ではないので、どのような対価を払っても避けるべきです。。しかし、コードが乱用されないと信じると、次のようになります。
wrap_this(){
run_something
eval "$(cat /dev/stdin)"
run_something_else
}
これにより、次のようなコードを実行できます。
wrap_this << EOF
my function
EOF
内部ブロックは文字列なので完全に理想的ではありませんが、再利用可能です。
答え3
いいえ、bashには匿名機能はありません。ただし、関数名と引数を文字列として渡し、bashでそれを呼び出すことができます。
function wrap() {
do_before
"$@"
do_after
}
wrap do_something with_arguments
しかし、これはやや制限的です。参照の処理が問題になる可能性があります。複数のコマンドを渡すことも複雑な問題です。
答え4
unset
関数を定義して使用した直後に呼び出すと、関数を削除できます。これは真の匿名機能を生成しませんが、呼び出しサイトの近くの外部では機能を使用できません。
function anon_fn {
echo 123
}
anon_fn
unset anon_fn