배열에 검색 내용 추가

배열에 검색 내용 추가

현재 find 출력을 기반으로 R 명령을 생성하는 스크립트가 있습니다.

#!/bin/bash
PATHX="/path/to/my/files"
find "${PATHX}" -maxdepth 1 -type f -name "*.csv" | while read d; do
FN=$(echo -n "${d}" | cut -d/ -f5 | cut -d. -f1)
echo "${FN}<-read.csv(\"${PATHX}/${FN}.csv\",header=TRUE)"
# <snip> etc .etc. etc.
echo "${FN}_2y<-tail(${FN}_log,730)"
done

이것은 훌륭하게 작동합니다. 하지만 R 명령을 사용하면 문제가 발생했습니다.

df<-data.frame(list,of,columns,goes,here)

이것을 위의 find/while에 통합하는 방법을 모르겠습니다. 즉, 목록을 출력해야 합니다.${FN}_2년data.frame() 함수를 입력하세요.

예를 들어 내 스크립트가 다음과 같이 출력된다고 가정해 보겠습니다.

  • a_2y
  • b_2y
  • c_2y

df<-data.frame(a_2y,b_2y,c_2y) 로 끝나야 합니다.

의견의 질문을 더 명확히 하기 위해 모든 csv 입력이 구문 분석된 후 마지막에 하나의 data.frame 인스턴스만 필요합니다.

답변1

이름을 변수로 수집 fns하고 끝에 해당 변수를 에코할 수 있습니다. 파이프가 있으므로 변수를 while/do/done과 동일한 하위 쉘에 유지해야 합니다. ${fns:1}초기 추가 쉼표가 제거된 변수의 하위 문자열입니다.

#!/bin/bash
PATHX="/path/to/my/files"
find "${PATHX}" -maxdepth 1 -type f -name "*.csv" |
(   fns=
    while read d; do
        FN=$(echo -n "${d}" | cut -d/ -f3 | cut -d. -f1)
        echo "${FN}<-read.csv(\"${PATHX}/${FN}.csv\",header=TRUE)"
        # <snip> etc .etc. etc.
        echo "${FN}_2y<-tail(${FN}_log,730)"
        fns+=",${FN}_2y"
    done
    echo "df<-data.frame(${fns:1})"
)

답변2

이런 종류의 작업은 쉘 스크립트에서 수행하기가 더 쉽습니다(비록 awk배열을 지원하는 bash와 같은 것을 사용하는 경우 배열 없이 무언가를 사용하는 것보다 조금 더 쉽습니다. 인용 및 와일드카드를 사용하거나 확장을 원하지 않습니다). 확장하는 대신 쉘 스크립트 또는)perlshwhichshperlawk

예를 들어:

#!/usr/bin/perl

use strict;

my $pathx='/path/to/my/files';

my $dh;
my @frames=();

# get list of .csv files from $pathx
opendir($dh, $pathx) || die "can't open directory '$pathx': $!\n";
my @csvfiles = grep { /\.csv$/ && -f "$pathx/$_" } readdir($dh);
closedir($dh);

foreach my $f (@csvfiles) {
   my @fields=split(/\./,$f);
   my $fn=$fields[@fields-2];   # perl array indices start from 0, not 1.

   printf '%s<-read.csv("%s",header=TRUE)'."\n", $fn, "$pathx/$f";
   # <snip> etc .etc. etc.
   printf '%s_2y<-tail(%s_log,730)'."\n", $fn, $fn;

   push @frames,"${fn}_2y";
}

print "df-<data.frame(", join(',',@frames), ")\n";

참고: 디렉터리 재귀가 필요한 경우 File::Find단순 모듈 대신 이 모듈을 사용할 수 있습니다.readdir()

출력 예(파일 a.csvb.csv) c.csv:

a<-read.csv("/path/to/my/files/a.csv",header=TRUE)
a_2y<-tail(a_log,730)
b<-read.csv("/path/to/my/files/b.csv",header=TRUE)
b_2y<-tail(b_log,730)
c<-read.csv("/path/to/my/files/c.csv",header=TRUE)
c_2y<-tail(c_log,730)
df-<data.frame(a_2y,b_2y,c_2y)

또는 다음과 같이 awk:

참고: awk에는 함수가 없으므로 join()함수를 작성해야 했습니다. 함수 도 awk없으므로 readdir()가장 쉬운 방법은 's의 출력을 파이프 find로 파이프하는 것입니다( sh필요한 경우 이를 수행하기 위한 래퍼 스크립트 작성).

#!/usr/bin/awk -f

BEGIN {
  FS="[./]";
  delete A; # has side-effect of defining A as an array
};   

# i isn't an argument to this function, it's a local variable.
# in awk, extra whitespace separates function args from declaration
# of local variable(s)

function join(array,sep,       i) {     
  result=array[1];     # awk array indices start from 1
  for (i=2;i<=length(array);i++) result = result sep array[i];
  return result;
};

# main code block, run on every input line
{
  fn=$(NF-1);
  printf "%s<-read.csv(\"%s\",header=TRUE)\n", fn, $0;
  # <snip> etc .etc. etc.
  printf "%s_2y<-tail(%s_log,730)\n", fn, fn;
  A[length(A)+1] = sprintf("%s_2y",fn);
};

END {
  print "df-<data.frame(" join(",",A) ")";
}

예를 들어 다른 이름으로 저장하여 myscript.awk실행 가능하게 만들고 다음 chmod과 같이 실행합니다.

find "${PATHX}" -maxdepth 1 -type f -name "*.csv" | ./myscript.awk

출력은 version 과 동일합니다 perl.

마지막으로 bash에서 동일한 알고리즘을 사용합니다.

#!/bin/bash

PATHX="/path/to/my/files"

declare -a frames=()
# get list of .csv files and store in array csvfiles.
csvfiles=( $(find "$PATHX" -maxdepth 1 -type f -name '*.csv' ) )

function join() {
  local sep result i
  sep="$1" ; shift
  result="$1" ; shift

  for i in "$@" ; do result="$result$sep$i" ; done
  printf '%s' "$result"
}

for f in "${csvfiles[@]}" ; do
  fn=$(basename "$f" '.csv')

  printf "%s<-read.csv(\"%s\",header=TRUE)\n" $fn $f;
  # <snip> etc .etc. etc.
  printf "%s_2y<-tail(%s_log,730)\n" $fn $fn;

  frames+=( "${fn}_2y" )
done

echo 'df-<data.frame('$( join ',' "${frames[@]}" )')';

이는 while read쉘 스크립트에서 일련의 행을 처리하는 데 거의 항상 최악의 방법인 루프를 방지합니다. 루프 사용을 피하는 모든 것 - 배열 주위에 awk또는 perl또는 또는 루프를 사용하십시오.sedforwhile read

관련 정보