나의 궁극적인 목표는 모든 파일에서 각 사용자 이름의 인스턴스를 계산하는 스크립트를 만드는 것입니다.
사용자 이름은 "login"이라는 문자열 뒤에 오는 따옴표로 묶인 문자열입니다. 예를 들어 파일에 다음이 있을 수 있습니다.
{"this":"is', {"a":"strange"}, "type":{"of":"object", "but":"please"},
"go":"withit", "login":"username1"}
{"this":"is', {"login":"username2"}, "type":{"of":"object", "but":"please"},
"go":"withit"}
다른 파일에는 다음이 있을 수 있습니다.
{"this":"is', {"a":"strange"}, "type":{"of":"object", "but":"please"},
"go":"withit", "login":"username3"}
{"login":"username1", "please":"gowithit"}
이 경우 각 사용자 이름이 파일에 나타나는 횟수를 포함하는 dict 개체가 포함된 txt 파일이 필요합니다.
{"username1": 2, "username2":1, "username3":1}
나는 여러 가지를 읽었습니다.물건도착하다얻다나시작, 하지만 합칠 수는 없는 것 같습니다. 의사 코딩을 했지만 이 시점에서는 더 이상 진행할 수 없습니다.
내 생각에는 이 작업을 두 단계로 나누어 수행해야 한다고 생각합니다.
1) 모든 사용자 이름 목록을 가져옵니다.
2) 각 사용자 이름이 모든 파일에 나타나는 횟수를 셉니다.
작업 1)의 경우:
grep 'login:' * | sed 's/^.*: //'
#Except I think this gets everything from the line after 'login', which isn't what I want.
작업 2)의 경우:
for all_usernames_in_file:
stringval = username_read_from_saved_file
cat * | grep -c $stringval > output.txt
누구든지 여기서 가져갈 수 있나요?
편집하다:
내가 이렇게 해야 한다는 뜻이군요:
grep -o 'login":"[^"]*"' /path/to/dir/* | cut -d'"' -f3 | sort | uniq -c | sed '1i{ s/\s*\([0-9]*\)\s*\(.*\)/"\2": \1,/;$a}' > output.txt
편집 2: 여전히 작동하지 않습니다. 각 명령어가 어떤 역할을 하는지 이해하여 진단해 보려고 합니다.
이 부분부터 시작한다고 가정 해 보겠습니다.
grep -o 'login":"[^"]*"' /path/to/dir/* | cut -d'"' -f3 | sort | uniq -c > myfile.txt
이제 myfile.txt
비어 있습니다.
나는 명령이 다음을 수행하고 있다고 생각합니다.
grep -o
일치하는 줄의 비어 있지 않은 부분과 일치합니다.
'login":"[^"]*"'
grep이 일치시키려는 문자열입니다. 중간에 있는 [^"]
것은 같지 않음 이후의 모든 문자와 일치합니다. 이는 모든 길이의 일치를 원한다는 것을 의미합니다. 즉, 사용자 이름의 길이는 중요하지 않으며 따옴표 사이의 모든 것을 원합니다.login":"
"
*
|
파이프라인이다. "그럼"이라는 뜻
cut -d '"' -f3
login":"
구분 기호를 사용하여 반환된 행( 이후의 모든 항목)을 분할 "
하고 필드 3(예: 사용자 이름만)을 사용하는 것을 의미합니다.
|
파이프라인이다. "그럼"이라는 뜻
sort
사용자 이름
|
파이프라인이다. "그럼"이라는 뜻
고유한 사용자 이름을 얻고 각 사용자 이름의 발생 횟수를 계산합니다.
그렇게 많은 수를 가져와 > myfile.txt
끝에 a를 추가하면 사용자 이름과 각 사용자 이름의 발생 횟수가 포함된 txt 파일이 생성됩니다. 형식이 잘 지정되지는 않지만 있을 것입니다.
왜 그런 파일을 얻지 못합니까?
참고: .json.gz
서식이 지정된 파일을 검색해도 문제가 됩니까? 검색할 때 작동하도록 스크립트를 얻었 txt
지만 다른 형식을 통해서는 작동하지 않습니다.
답변1
로그인과 값을 항상 공백 없이 큰따옴표로 묶는다고 가정하면, 이는 grep 및 count의 구성입니다.
grep -o 'login":"[^"]*"' * | cut -d'"' -f3 | sort | uniq -c
그러면 여러 번 발생한 로그인 목록이 생성됩니다.
이제 이를 기반으로 필요한 json 형식을 구성해야 합니다. sed
당신을 위해 이것을 할 수 있습니다:
| sed '1i{
s/\s*\([0-9]*\)\s*\(.*\)/"\2": \1,/;$a}'
이렇게 하면 청크의 시작과 끝이 sed
배치 되고 출력이 원하는 json 형식으로 변경됩니다.{
}
uniq
UPD: 최종 명령은 다음과 같아야 합니다.
grep -o 'login":"[^"]*"' * | cut -d'"' -f3 | sort | uniq -c | sed '1i{
s/\s*\([0-9]*\)\s*\(.*\)/"\2": \1,/;$a}' > file.txt
답변2
모든 사용자 이름, 즉 login
다음 과 관련된 모든 문자열을 가져옵니다.올바른 형식의 JSON 문서, 문서 구조를 모르고:
jq -r '..|select(.login?).login' file.json
이를 여러 JSON 파일에 적용하고 결과를 정렬하고 계산합니다.
jq -r '..|select(.login?).login' *.json | sort | uniq -c
여기서 사용된 표현 jq
은
..
: 모든 키와 값을 재귀적으로 순회합니다.select(.login?)
: 키가 포함된 발견된 개체를 선택합니다login
..login
: 키의 값을 가져옵니다.
jq
위의 표현을 바탕으로 원하는 사전은 다음과 같습니다 .
jq -sr '[..|select(.login?).login]|group_by(.)|map({key:.[0],value:length})|from_entries' *.json
시험:
$ cat file.json
{"this":"is", "A":{"login":"username2"}, "type":{"of":"object", "but":"please"},
"go":"withit", "login":"me"}
$ jq -sr '[..|select(.login?).login]|group_by(.)|map({key:.[0],value:length})|from_entries' file.json
{
"me": 1,
"username2": 1
}
동일한 파일을 두 번 제공하십시오.
$ jq -sr '[..|select(.login?).login]|group_by(.)|map({key:.[0],value:length})|from_entries' file.json f
ile.json
{
"me": 2,
"username2": 2
}
단일 라인의 컴팩트한 출력을 얻으려면 jq
with를 사용하십시오 .-c
예제 파일의 경우 jq -sr '[..|select(.login?).login]' file.json
다음이 생성됩니다.
[
"me",
"username2"
]
이것으로 group_by(.)
주어진
[
[
"me"
],
[
"username2"
]
]
이 map({key:.[0],value:length})
섹션은 다음을 제공합니다.
[
{
"key": "me",
"value": 1
},
{
"key": "username2",
"value": 1
}
]
마지막으로 from_entries
최종 결과가 제공됩니다.
답변3
정규식 일치로 입력된 Perl 해시를 사용하는 방법은 JSON 모듈을 사용하여 다음을 변환할 수 있습니다.
$ perl -MJSON -lne '$h{$1}++ for /(?<="login":")(.*?)(?=")/g }{ print encode_json \%h' file1 file2
{"username3":1,"username2":1,"username1":2}
답변4
@rush 사용이 sed
내 셸에서 작동하지 않아서 이렇게 했습니다.
grep -Poh '(?<=login":")[^"]*' json* | sort | uniq -c | awk -v OFS=': ' 'BEGIN{print "{"}{print $2, $1}END{print"}"}' | sed -E 's/([0-9])$/\1,/g;s/:/\":/g;s/^([^{}])/\"\1/g'
sed
쉘이 명령문 내에서 이스케이프 및 인쇄를 허용하는 경우 "
배수를 수정할 수 있습니다 .awk
grep -Poh '(?<=login":")[^"]*' json* | sort | uniq -c | awk -v OFS=': ' 'BEGIN{print "{"}{print \"$2\", $1}END{print"}"}' | sed -E 's/([0-9])$/\1,/g'
awk
두 번째 스크립트에서 내 껍질이 질식했습니다. \"
왜인지는 모르겠지만 누군가가 나에게 말해 줄 것이라고 확신합니다.
저도 시도해봤는데 jq
json 파일에 멈췄어요. 구문 오류가 있는 것 같습니다.
"this":"is' #is written so I edited these to
"this":"is"
jq
저도 이런 구조는 마음에 안드네요 .
{"a":"strange"} # so I also edited these to
b: {"a":"strange"}
jq
이는 원본 파일이 편집한 내용과 일치해야 하는 경우에 작동합니다.
jq '.login' json* | sort | uniq -c | awk -v OFS=': ' 'BEGIN{print "{"}{print $2, $1}END{print"}"}' | sed -E 's/([0-9])$/\1,/g'