과거에는 bash 스크립트를 작성하기 위해 bash를 많이 사용하지 않았으며 현재는 읽기용으로 bash 스크립트를 사용하고 있습니다. 파일에는 csv 형식으로 저장된 많은 필드가 포함되어 있습니다. 아래의 첫 번째 스크립트는 파일의 모든 IP를 수집하지만 수집하는 데에도 어려움을 겪고 있습니다.지적 재산권또 다른 필드가 호출됩니다.회로망.. 내가 이것을 달성할 수 있는지 아는 사람이 있나요?
files=`ls | grep data_batch_`
for file in ${files[@]}
do
cat ${file} | cut -d , -f2 | grep -v "IP" > data_${file}
done
나는 성공하지 못한 채 부울 연산자를 추가해 보았습니다. 또한 더 많은 파이프를 시도했습니다. 저는 bash를 자주 사용하지 않기 때문에 일부 구문이 누락되었거나 이것이 허용되지 않는 이유를 이해하지 못할 수도 있습니다.
files=`ls | grep data_batch`
for file in ${files[@]}
do
cat ${file} | cut -d , -f2 | cut -d, -f3 | grep -v "IP" && "Network" > data_${file}
done
어떤 이유에서인지 이 작업을 수행하면 덮어쓰는 것 같습니다.지적 재산권가치를 부여하다회로망값을 동시에 저장하는 대신. 본질적으로 내가 원하는 것은 하나의 필드가 아닌 두 개의 필드를 파일에 인쇄하는 것이지만 그의 솔루션을 구현하는 방법을 잘 모르겠습니다. 어떤 팁이라도 도움이 될 것입니다.
내가 원하는 출력은 파일에 저장된 IP 주소 값과 네트워크 값입니다. 현재 내가 얻는 것은 IP뿐입니다. 아래는 원하는 출력입니다.
1.1.1.1
Network5
답변1
스크립트에 많은 문제가 있습니다.
files=`ls | grep data_batch_`
for file in ${files[@]}
do
cat ${file} | cut -d , -f2 | grep -v "IP" > data_${file}
done
백틱을 사용하지 마세요. 대신 사용하십시오
$()
. 동일한 작업을 수행하지만 참조를 중단하지 않으며 중첩될 수 있습니다.files
for
배열인 것처럼 루프에서 사용 하지만 배열은 아닙니다. 이를 스칼라 문자열(의 출력ls | grep ...
)로 정의합니다. 배열을 정의하려면 다음과 같이 괄호를 사용해야 합니다.files
이는 문자열로 정의됩니다 .$ files=$(echo 1 2 3) $ declare -p files declare -- files="1 2 3"
비록 이것이 배열로 정의되어 있지만:
$ files=( $(echo 1 2 3) ) $ declare -p files declare -a files=([0]="1" [1]="2" [2]="3")
mapfile
또는 (일명 )을 사용할 수 있습니다readarray
.$ mapfile -t files < <(printf "%s\n" 1 2 3) $ declare -p files declare -a files=([0]="1" [1]="2" [2]="3")
변수 확장을 큰따옴표로 묶으십시오. 중괄호를 사용하는 것은아니요인용된 대안. 바라보다공백이나 기타 특수 문자 때문에 쉘 스크립트가 멈추는 이유는 무엇입니까?그리고$VAR 대 ${VAR} 및 인용 여부이유가 있습니다.
두 번째 스크립트에서는 출력
cut -d, -f2
을cut -d, -f3
. 그건 작동하지 않습니다.첫 번째는
cut
하나의 필드(필드 2)만 출력합니다. 두 번째 항목은cut
입력에 필드가 하나만 있고(또는 쉼표가 없으므로 필드가 없음) 존재하지 않는 필드를 출력하도록 지시했기 때문에 정확히 동일하게 출력됩니다. 3. 실행한echo 1,2,3 | cut -d, -f2
다음 실행하면 다음과 같은 결과가echo 1,2,3 | cut -d, -f2 | cut -d, -f3
표시됩니다. 두 명령 모두 출력은 동일합니다.2
.두 개의 출력 필드를 사용하려면
cut -f
쉼표로 구분하여 나열하세요. 예를 들어:cut -d, -f2,3
그런데 를 사용하여 필드 범위를 지정할 수도 있습니다
-
. 예를 들어 필드 2~5를 출력하려면 다음을 사용할 수 있습니다cut -d, -f2-5
. 바라보다man cut
.이것이 문제인지는 모르겠지만, 알아두셔야 할 부분입니다. 스크립트는 입력 파일과 이름이 같지만 접두사가 붙은 출력 파일로 stdout을 리디렉션합니다
data_
. 따라서 입력 파일data_batch_1.csv
이data_data_batch_1.csv
.이것이 바로 당신이 원하는 것일 수 있으며, 이 경우에는 문제가 되지 않습니다. 그러나 이는 스크립트를 다시 실행하면 파일 glob이 원래 입력 파일과 일치한다는 것을 의미합니다.그리고첫 번째 실행에서는 출력 파일이 생성됩니다. 결과적으로
data_data_data_batch_1.csv
.
그럼에도 불구하고 이것이 문제입니다. 다음은 몇 가지 해결 방법입니다. 다음과 같은 방법을 더 시도해 보세요.
for file in *data_batch_*; do
cut -d, -f2,3 "$file" | grep -v IP > "data_$file"
done
파일 이름 배열을 실제로 사용하려면 예를 들어 mapfile
및 를 사용할 수 있습니다.find
-print0
mapfile -t -d '' files < <(find . -maxdepth 1 -type f -name '*data_batch_*' -print0)
for file in "${files[@]}"; do
cut -d, -f2,3 "$file" | grep -v IP > "data_$file"
done
awk
또는 다음을 대신 사용할 수 있습니다 cut
.
awk -F, -v OFS=, '$2$3 !~ /IP/ { print $2, $3 > "data_" FILENAME }' *data_batch_*
$2
"IP" 나 "IP" 가 모두 포함되지 않은 경우 현재 파일 이름(awk의 변수)과 동일한 이름을 가진 파일로 리디렉션되고 "data_"라는 문자열이 앞에 붙은 $3
stdout을 사용하여 인쇄됩니다 .FILENAME
cut
이는 처리하는 각 파일에 대해 한 번씩 여러 번 분기 하고 grep
수행할 필요가 없기 때문에 훨씬 더 빠릅니다 .
마지막으로, CSV 파일에는 큰따옴표로 묶인 문자열 필드가 포함될 수 있으며 종종 포함됩니다. 이러한 인용된 필드에는 쉼표가 포함될 수 있습니다. 따옴표가 없고 쉼표가 포함된 필드가 없는 간단한 쉼표로 구분된 파일은 를 사용하여 안정적으로 처리할 수 있습니다 cut
. 모든 선택적 추가 기능이 포함된 실제 CSV에는 CSV 파서가 필요합니다. 가장 좋은 방법은 다음을 사용하는 것입니다.
답변2
awk를 사용할 수 있는 경우:
$ cat /tmp/abc
name1,0.0.0.0,NetworkName1
name2,0.4.2.3,NetworkName2
name3,0.1.43.5,NetworkName3
$ awk 'BEGIN { FS = "," } ;{printf $2","$3"\n"}' /tmp/abc
0.0.0.0,NetworkName1
0.4.2.3,NetworkName2
0.1.43.5,NetworkName3
따라서 이 경우에는
for i in $(ls | grep -E ^test.*[.]csv$)
do
cat $i | cut -d , -f2,3 >> testing.txt
done
될 수 있다
$ awk 'BEGIN { FS = "," } ;{printf $2","$3"\n"}' test*.csv > testing.txt
구조화된 텍스트 처리를 많이 한다면 awk를 배우는 데 시간을 투자하는 것이 도움이 될 것입니다.
답변3
나는 다음과 같은 행운을 누렸습니다.
디렉토리 내용:
$ ls
test.csv test1.csv test3csv test5.txt
각 파일에는 다음과 같은 줄이 포함되어 있습니다.
name1,0.0.0.0,NetworkName1
name2,0.4.2.3,NetworkName2
name3,0.1.43.5,NetworkName3
스크립트:
for i in $(ls | grep -E ^test.*[.]csv$)
do
cat $i | cut -d , -f2,3 >> testing.txt
done
이렇게 하면 test로 시작하고 로 끝나는 모든 파일을 가져와서 .csv
필드 2와 3을 제거하고 파일에 추가합니다 testing.txt
.
그 이후의 출력 파일은 다음과 같습니다.
0.0.0.0,NetworkName1
0.4.2.3,NetworkName2
0.1.43.5,NetworkName3
각 IP 주소와 각 네트워크 이름을 별도의 줄에 나열합니다.
스크립트에서 출력 파일의 내용을 덮어쓰는 이유는 현재 >
파일의 모든 내용을 덮어쓰는 연산자를 사용하고 있기 때문입니다. 반면에 원하는 것은 >>
파일 끝에 텍스트를 추가하는 연산자일 것입니다. 파일의.