For-loop - 배열 이름에 반복자가 있는 배열에 추가

For-loop - 배열 이름에 반복자가 있는 배열에 추가

다음과 같은 문제가 있습니다. arr일부 값이 포함된 배열이 있습니다 . 각 값을 서로 다른(이미 선언된) 배열 집합 earr$j, 즉 arr[0]in earr1, arr[1]into earr2및 일반적으로 arr[j-1]into 으로 정렬하고 싶습니다 earr$j. (나중에 비슷한 요소를 arr대상 요소의 다음 요소로 추가하게 됩니다 earr$j.) 나는 다음 코드 조각(더 큰 코드의 일부)을 사용하여 그렇게 하려고 했습니다.

for j in $(seq 1 $number_of_elements); do earr$j+=(${arr[j-1]}); done

나는 들었습니다 (내 게시물 "https://unix.stackexchange.com/questions/675454/for-loop-and-appending-over-list-of-arrays"참조). 마치 2를 만들려는 것처럼 보입니다. -D 배열(Bash는 지원하지 않음). Bash 구문을 제대로 사용하지 않은 결과가 무엇을 의미하든 관계없이 이것이 내 의도가 아니라는 점을 강조합니다. 내 이전 게시물이 문제를 제대로 설명하지 않았기 때문에 이것을 다시 게시하고 있습니다.

답변1

문자 그대로 질문에 대답하려면 일반적으로 다음 작업이 필요합니다 eval.

for i in "${!arr[@]}"; do
  eval '
    earr'"$i"'+=( "${arr[i]}" )
  '
done

eval위험하지만 올바르게 사용하면 안전합니다. 실수의 위험을 제한하는 좋은 접근 방식은 확실히 필요한 부분을 제외하고 모든 것을 작은따옴표로 인용하고 작은따옴표 안에 있지 않은 부분을 확인하는 것입니다(여기서는 $i대신 큰따옴표로 묶여 있으며 다음으로 확장됩니다). 변수 의 내용 i)은 전적으로 귀하의 통제하에 있습니다. 이 경우 우리는 숫자만 포함한다는 것을 알고 있으므로 이는 쉘 코드로 평가되는 $i임의의 데이터가 아닙니다 ( 단순히 작은따옴표를 제외하고 싶지 않은 것과 비교하십시오).eval${arr[i]}

2D 배열이 적합하지 않다고 말하는 이유를 아직도 모르겠습니다. ksh93( bashksh93에서 대부분의 구문을 복사했지만 다차원 배열은 복사하지 않았습니다) 에서는 다음을 수행합니다.

for i in "${!arr[@]}"; do
  earr[i]+=( "${arr[i]}" )
done

어쨌든 쉘을 사용해야 하는 특별한 이유가 없는 한, perl또는 와 같은 적절한 프로그래밍 언어를 사용하는 것이 더 나을 것 같다는 @cas의 의견에 동의합니다 python.

답변2

다음은 Perl 및 HoAoA(Hash-of-Array-of-Arrays) 데이터 구조를 사용하여 설명한 작업을 수행하는 방법에 대한 예입니다.

이를 이해하는 데 도움이 되도록 다음 매뉴얼 페이지가 유용합니다: perldata(perl 데이터 유형), perldsc(데이터 구조), perllol(lol = 목록 목록), perlref(참조) 및 perlreftut(참조에 대한 자습서). 또한 perldoc명령(예: perldoc -f opendir또는 ) 을 사용하여 특정 Perl 기능에 대한 세부 정보를 얻을 수도 있습니다 perldoc -f grep.

스크립트에 사용 된 sortgrep는 내장 Perl 함수입니다. 그들은~ 아니다및 명령줄 도구...원하는 경우 Perl에서 해당 도구를 호출할 수 있습니다(백틱이나 따옴표, 함수 또는 파이프를 여는 함수 및 기타 여러 방법을 사용하여) sort. 이 모든 것에 대한 자세한 내용을 확인하려면 사용하세요 .grepqxsystem()open()perldoc

$ cat HoAoA.pl 
#!/usr/bin/perl

use strict;
use Data::Dump qw(dd);

# $h is a ref to Hash-of-Array-ofArrays (HoAoA).
#
# This will be a data structure with the directory names
# (Folder1, Folder2, Folder3) as the hash keys of the top-level
# hash.  Each element of that hash will be an array where the
# indexes are the line numbers of the data.txt files in each
# of those directories. The data in these second-level arrays
# will be an array containing the three values in each line of
# data.txt: $$h{directory}[line number][element]
my $h;

# get the directory name from the first command line arg, default to ./
my $dir = shift // './';

# get a list of subdirectories that contain 'data.txt',
# excluding . and ..
opendir(my $dh, "$dir") || die "Couldn't open directory $dir: $!\n";
my @dirs = sort grep { $_ !~ /^\.+$/ && -d $_ && -f "$_/data.txt" } readdir($dh);
closedir($dh);

dd \@dirs;   # Data::Dump's dd function is great for showing what's in an array
print "\n";

foreach my $d (@dirs) {
  my $f = "$d/data.txt";
  open(my $fh,"<",$f) || die "Couldn't open file $f: $!\n";
  my $lc=0;  # line counter
  while(<$fh>) {
    chomp;   # strip trailing newline char at end-of-line
    my @row = split /\s*,\s*/;   # assume simple comma-delimited values
    push @{ $$h{$d}[$lc++] }, @row;
  }
  close($fh);
}

# dd is even better for showing complex structured data
dd $h;
print "\n";

# show how to access individual elements, e.g. by changing the
# zeroth element of line 0 of 'Folder1' to 999.
$$h{'Folder1'}[0][0] = 999;

dd $h;
print "\n";

# show how to print the data without using Data::Dump
# a loop like this can also be used to process the data.
# You could also process the data in the main loop above
# as the data is being read in.
foreach my $d (sort keys %{ $h }) {   # `foreach my $d (@dirs)` would work too
  print "$d/data.txt:\n";
  foreach my $lc (keys @{ $$h{$d} }) {
    print "  line $lc: ", join("\t",@{ $$h{$d}[$lc] }), "\n";
  }
  print "\n";
}

참고: 위의 내용은 간단한 쉼표로 구분된 데이터 파일을 처리하기 위해 작성되었습니다. 모든 특이점과 복잡함(쉼표가 포함된 여러 줄의 큰따옴표 필드 등)이 있는 실제 CSV의 경우 다음을 사용하세요.텍스트::CSV기준 치수. 이는 핵심 Perl 배포판에 포함되지 않은 타사 라이브러리 모듈입니다. Debian 및 관련 배포판에서는 apt-get install libtext-csv-perl libtext-csv-xs-perl. 다른 배포판에도 비슷한 패키지 이름이 있을 수 있습니다. 또는 cpan(perl 코어에 포함된 라이브러리 모듈을 설치하고 관리하는 도구)를 사용하여 설치할 수 있습니다 .

또한 참고: 위 스크립트는데이터::덤프. 이는 구조화된 데이터를 덤프하는 데 유용한 타사 모듈입니다. 불행하게도 Perl 코어 라이브러리의 일부로 포함되어 있지 않습니다. 데비안 등에서 apt-get install libdata-dump-perl. 다른 배포판도 비슷한 패키지 이름을 갖습니다. 그리고 최후의 수단으로 cpan.

어쨌든 다음 폴더 구조와 data.txt 파일을 사용합니다.

$ tail */data.txt
==> Folder1/data.txt <==
1,2,3
4,5,6
7,8,9

==> Folder2/data.txt <==
7,8,9
4,5,6
1,2,3

==> Folder3/data.txt <==
9,8,7
6,5,4
3,2,1

HoHoA.pl 스크립트를 실행하면 다음과 같은 출력이 생성됩니다.

$ ./HoAoA.pl 
["Folder1", "Folder2", "Folder3"]

{
  Folder1 => [[1, 2, 3], [4, 5, 6], [7, 8, 9]],
  Folder2 => [[7, 8, 9], [4, 5, 6], [1, 2, 3]],
  Folder3 => [[9, 8, 7], [6, 5, 4], [3, 2, 1]],
}

{
  Folder1 => [[999, 2, 3], [4, 5, 6], [7, 8, 9]],
  Folder2 => [[7, 8, 9], [4, 5, 6], [1, 2, 3]],
  Folder3 => [[9, 8, 7], [6, 5, 4], [3, 2, 1]],
}

Folder1/data.txt:
  line 0: 999   2       3
  line 1: 4     5       6
  line 2: 7     8       9

Folder2/data.txt:
  line 0: 7     8       9
  line 1: 4     5       6
  line 2: 1     2       3

Folder3/data.txt:
  line 0: 9     8       7
  line 1: 6     5       4
  line 2: 3     2       1

관련 정보