내 변수에 여러 줄 문자열이 있습니다 $PAT
. $PAT
파일 내에서 검색해야 합니다 $FILE
. 그렇다면 삭제된 파일 $PAT
을 $FILE
인쇄해야 합니다 $PAT
. 찾을 수 없으면 $PAT
아무것도 인쇄되지 않습니다. $PAT
특수 문자가 포함되어 있고 문자 그대로 일치해야 하는지 알 수 없습니다 . 예를 들어 $PAT
이면 //\/\\|*
에서 정확히 동일한 8자 문자열을 검색해야 합니다 $FILE
.
실제 사용은 기존 파일/스크립트에 텍스트를 설치하고 제거하는 것입니다. $PAT
에 추가하려면 $FILE
이전에 추가되었는지 알고 싶습니다. $PAT
이미 있는 경우 $FILE
, 없이 출력하면 $PAT
쉽게 제거할 수 있습니다.
(Android 장치)에 이러한 스크립트가 필요한 유일한 시스템은 BusyBox입니다. Perl이나 기타 스크립팅 언어가 없습니다.
답변1
완전한 라인을 일치시키고 싶다면 $PAT
해결책이 있습니다. 완전한 라인이란 일치하는 경우 $FILE
세 개의 하위 파일(f1, f2 및 f3)로 분할할 수 있음을 의미합니다.
cat f1 f2 f3
예$FILE
,- f2는
$PAT
.
f1 및/또는 f3은 비어 있을 수 있습니다.
먼저 f2 파일을 만듭니다.
cat << EOF > f2
$PAT
EOF
그런 다음 $FILE과 f2를 비교하고 결과를 저장합니다.
diff $FILE f2 > diff_res
res=$?
0 이면 $res
f1과 f3은 비어 있고 $FILE은 $PAT와 같습니다. 이 경우 빈 파일을 원한다고 가정합니다.
diff_res
"" 로 시작하는 행이 포함된 경우 >
f2에는 최소한 $FILE에 없는 행이 포함됩니다. 테스트를 받아보세요:
grep -q '^> ' diff_res
test $? -eq 0 && echo "PAT not found"
diff_res
" "로 시작하는 행이 포함 되지 않으면 f2 >
의 모든 행은 $FILE에 있지만 연속되지 않을 수 있습니다. 연속형인 경우 diff_res
다음이 포함됩니다.
- ""로 시작하지 않는 한 줄
<
(f1 또는 f3이 비어 있는 경우) - 두 줄은 " "로 시작하지 않으며
<
첫 번째 줄은 항상1d
" " 또는 "1,"로 시작합니다.
이를 테스트하기 위해 다음이 있습니다.
nb=$(grep -v "^< " diff_res | wc -l)
if test $nb -gt 2; then
pat_found=0
elif test $nb -eq 1; then
pat_found=1
else
pat_found=$(sed -n -e '1{/^1d/p;/^1,/p}' diff_res | wc -l)
fi
그런 다음 pat_found가 1이면 $PAT가 없는 파일은 diff 결과이며, 여기에는 <
" "로 시작하고 다음 두 문자가 없는 줄만 포함됩니다.
grep '^< ' diff_res | cut -c 3-
완전하고 재구성된 스크립트는 다음과 같습니다.
# Output the desired result on stdin.
f2=/tmp/f2 # Use of PID or mktmp would be better'
diff_res=/tmp/diff_res # Use of PID or mktmp would be better'
cat << EOF > $f2
$PAT
EOF
diff $FILE $f2 > $diff_res
if test $? -ne 0; then
grep -q '^> ' $diff_res
if test $? -ne 0; then
nb=$(grep -v "^< " $diff_res | wc -l)
if test $nb -eq 1; then
grep '^< ' $diff_res | cut -c 3-
elif test $nb -eq 2; then
pat_found=$(sed -n -e '1{/^1d/p;/^1,/p}' $diff_res | wc -l)
test $pat_found -eq 1 && grep '^< ' $diff_res | cut -c 3-
fi
fi
fi
rm -f $f2 $diff_res
답변2
나는 당신이 메모리에 맞는 텍스트 파일을 다시 작성한다고 가정합니다(구성 파일을 다시 작성하는 것처럼 보입니다).
다음 스크립트는 쉘 내장 및 cat
. 파일 내용에서 첫 번째 발생을 뺀 내용을 인쇄합니다 $PAT
. $PAT
그렇지 않으면 아무것도 인쇄되지 않습니다.
contents=$(cat "$FILE")
case $contents in
*"$PAT"*)
echo "${contents%%$PAT*}${contents#*$PAT}";;
esac
이 코드 조각은 파일에 null 바이트가 포함되어 있지 않고 단일 개행 문자로 끝나며 대시로 시작하지 않는다고 가정합니다. 또한 패턴이 개행 문자로 끝나는 경우 파일 끝에서 패턴을 찾을 수 없습니다. 다음의 보다 복잡한 코드 조각은 임의의 텍스트 파일을 처리합니다.
contents=$(cat "$FILE"; echo a)
contents=${contents%a}
case $contents in
*"$PAT"*)
contents="${contents%%$PAT*}${contents#*$PAT}"
dashes=${contents%%[!-]*}
echo -n "$dashes"
echo -n "${contents#$dashes}";;
esac
(당신이 제안한 동작은 패턴 전체를 포함하는 파일과 빈 파일을 구별하는 것을 불가능하게 만듭니다.)
실제로 제안된 중간 기능을 사용하는 것보다 추가/제거 스크립트를 직접 구현하는 것이 더 쉽습니다.
contents=$(cat "$FILE"; echo a)
contents=${contents%a}
append=
case $contents in
*"$PAT"*) contents="${contents%%$PAT*}${contents#*$PAT}";;
*) contents="$contents$PAT"
esac
dashes=${contents%%[!-]*}
{ echo -n "$dashes"; echo -n "${contents#$dashes}"; } >"$FILE.new"
mv -- "$FILE.new" "$FILE"
답변3
파일을 문자별로 읽습니다. 해당 문자가 변수의 첫 번째 문자와 일치하면 다음 문자가 비교됩니다. 전체 변수가 일치하지 않는 경우 반환됩니다. 구현할 수도 있습니다더욱 발전된 알고리즘더 빠르게 실행하려면 언어가 쉘이기 때문에 어쨌든 매우 느릴 것입니다.