목록(또는 더 정확하게는 별도의 항목으로 처리하려는 하위 문자열이 새 줄로 구분되는 문자열)에 특정 간단한 함수를 적용해야 하는 경우가 많습니다. 예를 들어, stringToBeSearched
적절한 파일 이름 목록을 얻는 간단한 해결책은 다음과 같습니다.
grep -l "stringToBeSearched" *
그런 다음 원하는 하위 문자열을 받아들이는 다른 함수에 이를 공급하고 싶습니다. 이것을 시도하고 수행하기 위해 나는 예를 들어 다음과 같이 정의했습니다.
f () { echo $(sed 's/begin-\([0-9]*\).end/\1/' <<<$1) ;}
예를 들어 파일에서 숫자를 추출해야 합니다 begin-123.end
. 이와 같은 함수는 재사용되지 않으므로 정의하는 것을 피하고 싶지만 Mathematica에서는 소위 순수 함수에 해당하는 함수, 즉 #1 + #2 & for 형식을 찾을 수 없는 것 같습니다. 익명 함수에 두 개의 인수를 함께 추가합니다.
이 함수는 문자열에 적용될 때 내가 원하는 작업을 수행하므로 남은 유일한 단계는 이를 올바른 문자열 목록에 적용하는 것입니다. 사용할 수 있을 것 같아요
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
. 하나는 이름으로 호출되고 begin-1.end
하나는 이름으로 호출됩니다 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
string 을 포함하는 각 파일 이름에 대해 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