(단순화를 위해 읽을 파일이 첫 번째 인수인 것으로 가정합니다. $1
)
난 내가 원하는 걸 할 수 있어외부적으로그리고:
tempfile=$(mktemp)
awk '/^#/ {next}; NF == 0 {next}; {print}' "$1" > $tempfile
while read var1 var2 var3 var4 < $tempfile; do
# stuff with var1, etc.
done
awk
그러나 구성 파일을 구문 분석할 때마다 이를 호출해야 한다는 것은 터무니없는 것 같습니다. read
파일의 주석 줄이나 빈 줄을 무시 하는 방법이 있습니까 ?아니요외부 바이너리/잠재적인 성능 문제가 있습니까?
지금까지의 답변은 매우 도움이 됩니다! 명확히 말하면 임시 파일을 사용하고 싶지 않지만하다구성을 읽고 싶습니다.파일에서, 표준 입력이 아닙니다. 스크립트를 호출할 때 입력 리디렉션을 사용할 수 있다는 것을 잘 알고 있지만 여러 가지 이유로 제 경우에는 이것이 작동하지 않습니다.
읽을 입력을 소프트 인코딩하고 싶습니다. 예를 들면 다음과 같습니다.
configfile="/opt/myconfigfile.txt"
[ $# -gt 0 ] && [ -r "$1" ] && configfile="$1"
while read var1 var2 var3 var4 < "$configfile" ; do
...
configfile
하지만 이것을 시도하면 프로세스가 종료될 때까지 첫 번째 줄을 계속해서 읽습니다.
어쩌면 이것은 그 자체의 질문이어야 할 수도 있지만... 내가 하고 있는 일에서 줄이 바뀔 수도 있습니다. 내 실수는 어디에 있습니까?
답변1
이를 수행하기 위해 임시 파일이 필요하지 않으며 sed(또는 awk)는 쉘 케이스 명령문보다 주석 처리에 훨씬 더 유연합니다.
예를 들어:
configfile='/opt/myconfigfile.txt'
[ $# -gt 0 ] && [ -r "$1" ] && configfile="$1"
sed -e 's/[[:space:]]*#.*// ; /^[[:space:]]*$/d' "$configfile" |
while read var1 var2 var3 var4; do
# stuff with var1, etc.
done
# Note: var1 etc are not available to the script at this
# point. They are only available in the sub-shell running
# the while loop, and go away when that sub-shell ends.
이렇게 하면 주석(선행 공백 포함 또는 제외)이 제거되고 입력을 while 루프에 공급하기 전에 입력에서 빈 줄이 제거됩니다. 해당 줄의 주석과 줄 끝에 추가된 주석을 별도로 처리합니다.
# full-line comment
# var1 var2 var3 var4
abc 123 xyz def # comment here
이와 같은 전화 sed
나 작업은 awk
"어리석은" 일이 아니라 완전히 정상적인 일입니다. 이것이 바로 이 도구의 목적입니다. 성능에 관해서는 매우 작은 입력 파일을 제외하면 이 sed
버전이 훨씬 더 빠를 것이라고 확신합니다. 파이핑에는 sed
약간의 시작 오버헤드가 있지만 매우 빠르게 실행되는 반면 셸은 느립니다.
2022년 5월 3일에 업데이트됨:
while 읽기 루프(var1, var2, var3 등)에 설정된 변수는 while 루프가 끝나면 "범위를 벗어납니다". while 루프 내에서만 사용할 수 있습니다. while 루프는 구성 파일이 파이프로 연결되어 있기 때문에 서브셸에서 실행됩니다. 서브쉘이 죽으면 해당 환경과 하위 프로세스도 함께 사라집니다.할 수 없다상위 프로세스의 환경을 변경합니다.
while 루프 후에도 변수의 값이 유지되도록 하려면 파이프 사용을 피해야 합니다. 예를 들어 입력 리디렉션( <
) 을 사용하고프로세스 교체( <(...)
):
while read var1 var2 var3 var4; do
# stuff with var1, etc.
done < <(sed -e 's/[[:space:]]*#.*// ; /^[[:space:]]*$/d' "$configfile")
# remainder of script can use var1 etc if and as needed.
이 프로세스 대체 버전을 사용하면 while 루프가 상위 셸에서 실행되고 sed
스크립트는 하위 프로세스로 실행됩니다(해당 출력은 while 루프로 리디렉션됨). sed와 해당 환경은 완료 시 사라지지만 while 루프를 실행하는 셸은 루프에 의해 생성/변경된 변수를 유지합니다.
답변2
이는 공백(IFS)의 모든 항목이 삭제되기 때문에 작동합니다 read
. 따라서 var1이 비어 있거나 "#"으로 시작하면 건너뜁니다.
while read var1 var2 var3 var4; do
case $var1 in
''|\#*) continue ;; # skip blank lines and lines starting with #
esac
echo "var1: '$var1'"
# stuff with var1, etc.
done < "${1:-default_config_file}"
while
그러면 입력이 명령 목록 대신 루프로 리디렉션되어야 합니다 . 비어 있지 않으면 "${1:-default_config_file}"
첫 번째 명령줄 인수로 확장되고, 그렇지 않으면 다음으로 확장됩니다 default_config_file
. 기본값 문자열 등에서 변수 확장을 사용할 수도 있습니다.
최소한의 전처리에 관심이 있으므로 이것이 동일하다고 생각하지만 모든 주석도 제거합니다.
while read line; do
echo "${line%%#*}" | {
read var1 var2 var3 var4
[ -z "$var1" ] && continue
# stuff with var1, etc.
for i in 1 2 3 4; do eval echo "\"var$i: \$var$i\""; done #debug only!
}
done < "${1:-default_config_file}"
이는 쉘 매개변수 확장 하위 문자열 처리 기능을 사용합니다. 제거 후 첫 번째 값과 모든 항목을 제외하고 원래 값으로 확장됩니다 ${line%%#*}
. 로드하고 평소대로 계속하십시오. 이제 대신 빈 문자열만 확인하면 되므로 테스트가 단축됩니다.line
#
var1-4
continue
#
답변3
임시 파일을 만들지 않고도 이 작업을 수행할 수 있습니다. grep 명령은 빈 줄과 주석 줄을 필터링합니다.
while read var1 var2 var3; do
echo $var1
echo $var2
echo $var3
echo "etc..."
done < <(grep -v "^#\|^$" /opt/myconfigfile.txt)