CSV 끝에 임의의 값이 포함된 열 추가

CSV 끝에 임의의 값이 포함된 열 추가

사용자 목록이 포함된 CSV가 있고 각 사용자에게 고유하고 무작위로 생성된 일회성 비밀번호가 포함된 열을 추가하고 싶습니다.

내 스크립트는 작동하지만 계속해서 행을 계속 추가합니다. 변수를 설정하기 위해 코드를 루프 밖으로 이동하면 제대로 작동하지만 모든 사용자는 동일한 비밀번호를 얻습니다.

마지막 줄에서 종료되게 하려면 어떻게 해야 합니까?

#!/bin/bash
#add column to csv
ORIG_FILE="new-users2.csv"
NEW_FILE="Output.csv"
{ echo `head -1 $ORIG_FILE`",One Time Password" ; tail -n +2 $ORIG_FILE | \
  while read x ; OneTimePass=$(openssl rand -base64 14 | head -c 6) ; do echo "$x,$OneTimePass" ; done ; } > $NEW_FILE

답변1

루프 구문이 while...do...done잘못되었습니다. 당신은 이것을 실행하고 있습니다 :

while read x ; OneTimePass=$(openssl rand -base64 14 | head -c 6) ; do ...

키워드 의 예상 형식 while은 아래에 설명되어 있습니다 help while.

$ help while
while: while COMMANDS; do COMMANDS; done
    Execute commands as long as a test succeeds.
    
    Expand and execute COMMANDS as long as the final command in the
    `while' COMMANDS has an exit status of zero.
    
    Exit Status:
    Returns the status of the last command executed.

여기에서는 두 가지 명령을 제공합니다. read x ;그리고 OneTimePass=$(openssl rand -base64 14 | head -c 6)두 번째 명령은 항상 작동하며 언제든지 명령을 다시 실행할 수 있기 때문에 종료가 없습니다 openssl. 그렇기 때문에 while루프가 종료되지 않고 계속해서 더 많은 줄을 작성하게 됩니다. 당신이 추구하는 것은 이것입니다:

while read x; do
    something
done

다음은 올바른 인용 및 변수 이름의 대문자 사용 방지와 같은 몇 가지 기타 개선 사항을 포함하는 작업 버전의 스크립트입니다.

#!/bin/bash

#add column to csv
orig_file="new-users2.csv"
new_file="Output.csv"

printf "%s,%s\n" "$(head -1 "$orig_file")" "One Time Password" > "$new_file"
tail -n +2 "$orig_file" |
  while read -r x; do
    OneTimePass="$(openssl rand -base64 14 | head -c 6)"
    printf '%s,%s\n' "$x" "$OneTimePass"
  done >> "$new_file"

개인적으로 저는 파일 이름을 하드코딩하는 것은 스크립트를 사용하기 어렵게 만들고 활용도를 떨어뜨리므로 피하고 싶습니다. 입력 파일 이름을 인수로 취한 다음 stdout으로 인쇄하여 원하는 출력 파일을 선택할 수 있습니다.

#!/bin/bash

#add column to csv
orig_file=$1

printf "%s,%s\n" "$(head -1 "$orig_file")" "One Time Password"
tail -n +2 "$orig_file" |
  while read -r x; do
    OneTimePass="$(openssl rand -base64 14 | head -c 6)"
    printf '%s,%s\n' "$x" "$OneTimePass"
  done

그런 다음 다음과 같이 실행할 수 있습니다.

foo.sh new-users2.csv > Output.csv 

다음 입력 파일로 테스트했습니다.

$ cat new-users2.csv 
name,age
Bob,45
Alice,36

결과 :

$ foo.sh new-users2.csv 
name,age,One Time Password
Bob,45,BTkLQW
Alice,36,CzQa4U

답변2

사용밀러, 그리고 뻔뻔하게 빌린@terdon의 샘플 파일

$ mlr --csv put -S '
    $["One Time Password"] = substr(system("openssl rand -base64 5"),0,5)
' new-users2.csv 
name,age,One Time Password
Bob,45,kIrlrl
Alice,36,h1OBp3

( openssl rand6개의 Base64 문자를 생성하는 데 36비트 이상이 필요하지 않기 때문에 매개변수를 14바이트에서 5바이트로 변경했습니다. 어떤 이유로든 중요하다면 다시 변경하세요.)

awk의 기능을 사용하여 비슷한 작업을 수행할 수 있지만 system()CSV 구조와 헤더를 처리하는 것이 더 혼란스럽습니다. 아마도 awk를 사용하는 더 깔끔한 방법은 getline다음을 사용하는 것입니다.

$ awk -F, '
    BEGIN {OFS=FS; cmd = "openssl rand -base64 5"} 
    NR==1 {$(NF+1) = "One Time Password"} 
    NR >1 {cmd | getline var; close(cmd); $(NF+1) = substr(var,1,6)} 
    1
' new-users2.csv
name,age,One Time Password
Bob,45,CovLkz
Alice,36,PgLbD4

Miller 버전과 달리 이는 "간단한" CSV에서만 작동합니다(예: 필드에 포함된 "," 문자를 처리하지 않습니다).

관련 정보