awk ifs 및 변수 - 한 줄에서 다음 줄로 변수를 전달할 수 없습니다

awk ifs 및 변수 - 한 줄에서 다음 줄로 변수를 전달할 수 없습니다

우선 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 스크립트는 다음을 수행해야 합니다:

  1. :라인 에 어떤 것이 있는지 확인하십시오 .
  2. 그렇다면 문자열(제외 :)을 변수( $path내 경우에는) 에 할당합니다.
  3. 행이 비어 있으면 아무것도 인쇄되지 않습니다.
  4. 비어 있지 않고 인쇄 내용이 없으면 현재 줄을 :인쇄합니다 .$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는 변수 이름을 해당 값으로 확장하는 데 사용되지 않고 대신 행의 필드를 참조합니다( 와 유사).bashmakeawk$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할 필요가 없으며 정의되지 않은 변수는 컨텍스트에 따라 기본적으로 또는 로 설정됩니다.pathBEGIN""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}'

관련 정보