![awk ifs 및 변수 - 한 줄에서 다음 줄로 변수를 전달할 수 없습니다](https://linux55.com/image/63309/awk%20ifs%20%EB%B0%8F%20%EB%B3%80%EC%88%98%20-%20%ED%95%9C%20%EC%A4%84%EC%97%90%EC%84%9C%20%EB%8B%A4%EC%9D%8C%20%EC%A4%84%EB%A1%9C%20%EB%B3%80%EC%88%98%EB%A5%BC%20%EC%A0%84%EB%8B%AC%ED%95%A0%20%EC%88%98%20%EC%97%86%EC%8A%B5%EB%8B%88%EB%8B%A4.png)
우선 awk를 처음 접하는 초보라서 간단한 내용이라도 양해 부탁드립니다.
경로가 포함된 파일을 생성하려고 합니다. ls -LT
이를 위해 매니페스트와 awk 스크립트를 사용했습니다 .
다음은 입력 파일의 예입니다.
vagrant@precise64:/vagrant$ cat structure-of-home.cnf
/home/:
vagrant
/home/vagrant:
postinstall.sh
예상되는 결과는 다음과 같습니다.
/home/vagrant
/home/vagrant/postinstall.sh
awk 스크립트는 다음을 수행해야 합니다:
:
라인 에 어떤 것이 있는지 확인하십시오 .- 그렇다면 문자열(제외
:
)을 변수($path
내 경우에는) 에 할당합니다. - 행이 비어 있으면 아무것도 인쇄되지 않습니다.
- 비어 있지 않고 인쇄 내용이 없으면 현재 줄을
:
인쇄합니다 .$path
$0
스크립트는 다음과 같습니다.
BEGIN{
path=""
}
{
if ($1 ~ /\:/)
{
sub(/\:/,"",$1)
if (substr($1, length,1) ~ /\//)
{
path=$1;
}
else
{
path=$1"/"
}
}
else if (length($0) == 0)
{}
else
print $path$1
}
문제는 스크립트를 실행할 때 다음과 같은 혼란이 발생한다는 것입니다.
vagrant@precise64:/vagrant$ awk -f format_output.awk structure-of-home.cnf
vagrantvagrant
postinstall.shpostinstall.sh
내가 뭘 잘못했나요?
답변1
~처럼지적통과탈레진, 인쇄할 때 확장을 사용하는 것이 실수입니다 $
. 또는 와 달리 path
는 변수 이름을 해당 값으로 확장하는 데 사용되지 않고 대신 행의 필드를 참조합니다( 와 유사).bash
make
awk
$
perl
따라서 코드를 작동시키려면 이를 제거하세요.
BEGIN{
path=""
}
{
if ($1 ~ /\:/)
{
sub(/\:/,"",$1)
if (substr($1, length,1) ~ /\//)
{
path=$1;
}
else
{
path=$1"/"
}
}
else if (length($0) == 0)
{}
else
print path$1
}
그러나 이것은 실제로 좋은 해결책은 아닙니다 . 첫째, 규칙 에서 초기화 awk
할 필요가 없으며 정의되지 않은 변수는 컨텍스트에 따라 기본적으로 또는 로 설정됩니다.path
BEGIN
""
0
또한 다음을 awk
포함하는 모든 스크립트는무늬그리고행동, 전자는 의미언제, 후자의무엇해. 너가 하나 가지고 있네행동항상 실행됨(null무늬), 내부적으로 (중첩된) 조건을 사용하여 수행할 작업을 결정합니다.
내 솔루션은 다음과 같습니다
# BEGIN is actually a pattern making the following rule run only once:
# That is, before any input is read.
BEGIN{
# Split lines into chunks (fields) separated by ":".
# This is done by setting the field separator (FS) variable accordingly:
# FS=":" # this would split lines into fields by ":"
# Additionally, if a field ends with "/",
# we consider this part of the separator.
# So fields should be split by a ":" that *might*
# be predecessed by a "/".
# This can be done using a regular expression (RE) FS:
FS="/?:" # "?" means "the previous character may occur 0 or 1 times"
# When printing, we want to join the parts of the paths by "/".
# That's the sole purpose of the output field separator (OFS) variable:
OFS="/"
}
# First we want to identify records (i.e. in this [default] case: lines),
# that contain(ed) a ":".
# We can do that without any RE matching, since records are
# automatically split into fields separated by ":".
# So asking >>Does the current line contain a ":"?<< is now the same
# as asking >>Does the current record have more than 1 field?<<.
# Luckily (but not surprisingly), the number of fields (NF) variable
# keeps track of this:
NF>1{ # The follwoing action is run only if are >1 fields.
# All we want to do in this case, is store everything up to the first ":",
# without the potential final "/".
# With our FS choice (see above), that's exactly the 1st field:
path=$1
}
# The printing should be done only for non-empty lines not containing ":".
# In our case, that translates to a record that has neither 0 nor >1 fields:
NF==1{ # The following action is only run if there is exactly 1 field.
# In this case, we want to print the path varible (no need for a "$" here)
# followed by the current line, separated by a "/".
# Since we defined the proper OFS, we can use "," to join output fields:
print path,$1 # ($1==$0 since NF==1)
}
그게 다야. 모든 주석을 제거하고, 변수 이름을 줄이고, [O]FS
정의를 명령줄 매개변수로 옮기면 다음과 같이 간단하게 작성할 수 있습니다.
awk -F'/?:' -vOFS=\/ 'NF>1{p=$1}NF==1{print p,$1}' structure-of-home.cnf
답변2
awk -F: '/:/{prefix=$1;next}/./{print prefix "/" $0}'
/
경로에 double이 있는 것은 문제가 되지 않습니다.
하지만 원한다면 추가할 수 있습니다
awk -F: '/:/{sub("/$","",$1);prefix=$1;next}/./{print prefix "/" $0}'
또는
awk -F: '/:/{prefix=$1;s="/";if(prefix~"/$")s="";next}/./{print prefix s $0}'
답변3
나는 다음과 같은 일을 할 것입니다 :
awk 'match($0, "/*:$") {path = substr($0, 1, RSTART-1); next}
NF {print path "/" $0}'