Esse tipo de coisa é mais fácil de fazer em awk
ou perl
do que em um script de shell (embora se você estiver usando um sh
como bash which
suporta matrizes, é um pouco mais fácil do que usar um sh
sem arrays.Você ainda tem muito mais complicações com aspas e globbing ou expansão onde você não quer em um shell script do que em perl
ou awk
)
Por exemplo:
#!/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";
NOTA: você pode usar o módulo File::Find
em vez de um simples readdir()
se precisar de uma recursão de diretório.
Exemplo de saída (com os arquivos a.csv
, b.csv
e 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)
ou com awk
:
NOTA: o awk não tem uma função join()
, então eu tive que escrever um. awk
também não tem uma função readdir()
, então é mais fácil apenas enviar a saída de find
para ela (escreva um script wrapper sh
para fazer isso se necessário).
#!/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) ")";
}
salve como, por exemplo, myscript.awk
, torne-o executável com chmod
e execute como:
find "${PATHX}" -maxdepth 1 -type f -name "*.csv" | ./myscript.awk
A saída é idêntica à versão perl
.
Finalmente, o mesmo algoritmo no 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[@]}" )')';
Isso evita um loop while read
, que é quase sempre a pior maneira possível de processar uma série de linhas em um shell script. Use o laço awk
ou perl
ou sed
ou for
em torno de uma matriz - qualquer coisa para evitar o uso de um loop while read
.