リスト(またはより正確には、別々の項目として処理したい部分文字列が新しい行で区切られた文字列)に特定の単純な関数を適用する必要があることがよくあります。たとえば、stringToBeSearched
適切なファイル名のリストを取得する簡単な解決策は次のとおりです。
grep -l "stringToBeSearched" *
それから、あなたが望む部分文字列を受け入れる他の関数にそれを供給したいと思います。これを試して実行するために、私は例えば次のように定義しました。
f () { echo $(sed 's/begin-\([0-9]*\).end/\1/' <<<$1) ;}
たとえば、ファイルから数字を抽出する必要がありますbegin-123.end
。このような関数は再利用されないので、定義するのを避けたいのですが、Mathematicaではいわゆる純粋な関数に対応する関数、つまり#1 + #2 & forの型が見つからないようです。匿名関数に2つの引数を一緒に追加します。
この関数は文字列に適用されるときに私が望むことをするので、残りの唯一のステップはそれを正しい文字列リストに適用することです。使えると思います。
grep -l "stringToBeSearched" * | xargs -n1 f
xargsが関数fについて知らないので、これはうまくいかないようです。範囲が間違っていると思います。提案された解決策はf(https://stackoverflow.com/a/11003457/7238575)しかしそれは役に立たないようです。その他(https://stackoverflow.com/questions/11003418/calling-shell-functions-with-xargs)は新しいbashインスタンスも呼び出す必要があることを示唆しています。
しかし、私が試してみると
grep -l "stringToBeSearched" * | xargs -n1 bash -c f
ちょうど白い行のリストを印刷します。
明らかに、関数fをリストに適用するのと同じように、単純な操作を実行するより簡単な方法が必要です。
入力と出力の例:textを含むファイルがありますstringToBeSearched
。 1つは名前で呼び出され、begin-1.end
1つは名前で呼び出されますbegin-2.end
。このファイルが含まれていないstringToBeSearched
アイテムに隠されているとしましょう。stringToBeSearched
したがって、この場合は1と2を含むリストを取得したいと思います。理想的には、上記の機能をf2
これらの機能に適用する簡単な方法も必要です。それで結局は走ることができるようになってほしいf2 1
」f2 2
これがXYの質問なら、技術的な質問に対する答えではなく、これがまったく方法ではない理由を説明する答えが欲しいです。質問のポイントは、私が探している数字を見つける方法ではありません(私は答えが欲しいが)。リストに関数を適用する一般的な方法が何であるかを尋ねます。上記の特定の問題は、リストの操作に関数を適用する必要がある問題の一例にすぎません。リストに関数を適用できない問題を説明するためのものです。これは本質的に主な問題ではありません。
答え1
リストに関数を適用するには、そのリストを繰り返すだけです。
list=(one two 'twenty one' banana)
f() {
echo "This is f applied to '$1'"
}
for item in "${list[@]}"
do
f "$item"
done
(スペース)で区切られたリストがある場合は、それを配列(リスト)に変換するか、段階的に実行できます。ワイルドカード(*
、、、?
... [
)を含むここに引用符がないリストのすべての項目は、]
現在のディレクトリのコンテキストで通常どおりに評価されるため、最初にその配列を無効にする必要があります(これは非常に便利な妥当な理由です)。区切り文字列の代わりに /list):
text='one two twenty-one banana'
OIFS="$IFS" IFS=' ' OSHELLOPTS="$SHELLOPTS"
set -o noglob
for item in $text
do
f "$item"
done
IFS="$OIFS"
[[ ! "$OSHELLOPTS:" =~ [=:]noglob: ]] && set +o noglob
バリエーションが多いです。コロンで区切られたリストは次のとおりです。
text='one:two:twenty one:banana'
OIFS="$IFS" IFS=':' OSHELLOPTS="$SHELLOPTS"
set -o noglob
...
答え2
純粋な関数とカリングについてのこのすべての話と一流の関数を持つ言語には悪いことがありますが、シェルスクリプトの場合、パイプはあなたが見つける必要があります。
入力から行のインポート、Xの実行、出力などを明示的に話す必要がある場合は、一歩下げるか、現在行っている操作を再確認する必要があります。ほとんどの標準ツールは自動的に入力から行を取得し、Xと出力を実行するため、通常は正しいツールと正しいXを取得できます。したがって、入力から行を取得する状況が発生した場合は、入力から行を取得できるツールへの入力として使用し、そのコマンドの出力をキャプチャして出力に再利用します。間違った。
この場合、つまりsed
Xはです's/begin-\([0-9]*\).end/\1/'
。
また注:echo $(sed ...)
何の意味もありません。ちょうどやってくださいsed ...
。コマンド置換を使用して出力をキャプチャし、再び出力として使用します。
答え3
文字列を含む各ファイル名のN
ファイル名の整数を取得したいようです。begin-N.end
stringToBeSearched
簡単なループでこれを行うことができます。
for filename in begin-*.end; do
if grep -qF 'stringToBeSearched' "$filename"; then
N=${filename%.end}
N=${N#begin-}
printf '%s\n' "$N"
fi
done
焦点は私達にあるいいえ繰り返しテキスト。ファイル名を含むテキスト(の出力grep -l
)は、Unixシステムで利用可能なすべてのファイル名、特に改行文字を含むファイル名を非常に正しくエンコードしません。
代わりに、私たちはglobパターンを次begin-*.end
のように拡張します。正しいリストこれを繰り返してリスト内の各要素をテストし、一致するものが見つかったgrep
場合は整数を抽出します。
必要に応じてこれを関数でラップできます。
test_files () {
local func="$1"; shift
local string="$1"; shift
# Looks for the string "$string" in all given files.
# Calls "$func" with each pathname that contains the string.
for pathname do
if grep -qF "$string" "$pathname"; then
"$func" "$pathname"
fi
done
}
foo () {
# Takes a string on the form "begin-N.end" and
# extracts and prints "N".
local tmp="${1%.end}"
printf '%s\n' "${tmp#begin-}"
}
test_files foo stringToBeSearched begin-*.end
foo
これは、特定の文字列を含むすべてのファイルに対して呼び出される単純な形式の「コールバック」を使用します。test_files
答え4
リストがある場合、コマンドを並列に実行すると利点が得られることがよくあります。
env_parallel --session
f () { echo $(sed 's/begin-\([0-9]*\).end/\1/' <<<$1) ;}
grep -l "stringToBeSearched" * | env_parallel f
または:
f () { echo $(sed 's/begin-\([0-9]*\).end/\1/' <<<$1) ;}
export -f f
grep -l "stringToBeSearched" * | parallel f