FILE1=$1
FILE2=$2
if [ ! -e "$FILE2" ]
then
touch $FILE2
fi
while read line; do
if grep -q "$line" $FILE2
then
echo
else
echo $line >> $FILE2
fi
done < $FILE1
FILE1의 행이 FILE2에 없으면 FILE2에 추가하고 싶습니다. 내 목적은 FILE1의 행을 나열하고 해당 행이 FILE2에 없으면 FILE2에 추가하는 것입니다.
뭐가 문제 야?
답변1
awk 'NR == FNR {first[$0];next}; ! ($0 in first)' "$file2" "$file1" >> "$file2"
파일 이름에 =
문자가 없다고 가정합니다. 가능하다면 /dev/fd/n을 지원하는 시스템에서 다음을 수행할 수 있습니다.
awk 'NR == FNR {first[$0];next}; ! ($0 in first)' \
/dev/fd/3 3< "$file2" /dev/fd/4 4< "$file1" >> "$file2"
$file1
행이 에서 여러 번 발생하고 에서는 발생하지 않는 경우 $file2
모든 발생은 에 추가됩니다 $file2
. 이것이 원하는 것이 아니라면 다음을 수행하십시오.
awk 'NR != FNR && ! ($0 in seen); {seen[$0]}' \
/dev/fd/3 3< "$file2" /dev/fd/4 4< "$file1" >> "$file2"
행이 고유하고 출력 정렬에 문제가 없으면 다음을 수행할 수도 있습니다.
LC_ALL=C sort -uo "$file2" "$file1" "$file2"
코드에 어떤 문제가 있는지:
FILE1=$1 FILE2=$2
관례적으로 모든 대문자 변수는 예약되어 있습니다.환경변수(공유 네임스페이스로 환경에 내보낸 변수)이므로 쉘 변수에만 대문자 변수를 모두 사용하지 않는 것이 가장 좋습니다.
if [ ! -e "$FILE2" ] then touch $FILE2 fi
의 매개변수에서는 참조했지만 [
의 매개변수에서는 참조하지 않았습니다 touch
. 이유는 무엇입니까?
또한 그러하니 참고해주세요
touch "$file_or_option"
변수가 항상 파일 매개변수로 처리되도록 하려면 다음을 수행해야 합니다.
touch -- "$file2"
그리고 이는 if ! condition; then do-something-to-make-it-true
일반적으로 나쁜 습관이며 경쟁 조건의 영향을 받습니다. 이렇게 하는 것이 더 좋습니다 enforce-the-condition || die-if-couldn't
. 그래서 여기 있습니다:
touch -- "$file2" || exit
그러나 이에 관계없이 >>
리디렉션은 파일을 생성합니다(만약 생성할 수 없는 경우 오류를 반환합니다).
while read line; do
쉘에서 루프를 사용하기 시작할 때특히 while read
루프, 이는 일반적으로 잘못된 접근 방식을 취하고 있음을 의미합니다. 파일의 각 줄에 대해 여러 명령을 순차적으로 실행하게 되는데, 이는 쉘 스크립트가 작성되는 방식이 아닙니다. 대신, 특정 특수 명령을 한 번 실행하고 싶습니다.협력작업에.
먼저 POSIX 쉘에서 a 를 읽으려면 line
구문은 다음과 같습니다.
IFS= read -r line
아니요
read line
if grep -q "$line" $FILE2
다시 말하지만, 그것은 다음과 같습니다:
grep -q "$option_or_regexp"
또는:
grep -q -- "$regexp"
또는:
grep -qe "$regexp"
정규식을 일치시키는 대신 문자열을 검색하려는 경우 또는 -F
전체 줄을 일치시키려는 경우 이 옵션이 필요합니다 -x
.
grep -qxFe "$line" < "$file2"
then echo else echo $line >> $FILE2
마찬가지로, Split+glob 연산자를 적용하는 대상 ( $line
sh 모드에서 $FILE2
사용 되지 않는 경우 bash
).
또한 echo
임의의 데이터와 함께 사용할 수 없습니다. 다음을 수행해야 합니다.
printf '%s\n' "$line" >> "$file2"
여기. 그러나 $file2
전체 루프에 대해 한 번만 수행할 수 있었는데 루프의 각 패스에 대해 다시 열면 낭비입니다 .
fi done < $FILE1
다시:
done < "$file1"
사용된 경우 bash
.