이 글을 읽어주셔서 진심으로 감사드립니다. 저는 bash를 처음 접했기 때문에 다음에 대한 조언이 필요합니다.
2개의 열이 포함된 파일을 읽는 bash 스크립트를 작성하고 싶습니다.
f 2
g 1
s 4
d 5
f 2
g 5
d 9
g 10
h 1
s 5
d 29
내 스크립트는 실제로 첫 번째 열(알파벳)을 기준으로 파일을 정렬하고 alpha_sorted.txt
이라는 파일을 생성한 다음 숫자로 동일한 작업을 수행하고 이름을 지정하기를 원합니다 numbers_sorted.txt
.
저는 이 분야에 매우 익숙하지 않기 때문에 가능하다면 여러분의 도움을 요청하고 싶고 문서나 링크를 제공하거나 코드에 대한 도움도 받고 싶습니다.
이 스크립트는 초급 수준 사용을 위한 것이므로 접근 방식을 복잡하게 만드는 것은 권장되지 않습니다.
고쳐 쓰다
john1024의 답변을 사용하여 다음 문제가 발생했습니다.
Hasan@HasanChr /cygdrive/c/users/Hasan/Desktop/Bash
$ chmod +x script.sh
Hasan@HasanChr /cygdrive/c/users/Hasan/Desktop/Bash
$ ./script.sh
cat: alpha_sorted.txt: No such file or directory
스크린샷입니다script.sh
답변1
이 글이 에 게시된 이후로유닉스.stackexchange.com, 일반적인 UNIX 도구에 액세스할 수 있다고 가정합니다.
첫 번째 열은 알파벳순으로 정렬됩니다.
$ sort file.txt >alpha_sorted.txt
$ cat alpha_sorted.txt
d 29
d 5
d 9
f 2
f 2
g 1
g 10
g 5
h 1
s 4
s 5
숫자 정렬:
$ sort -nk2,2 file.txt >numbers_sorted.txt
$ cat numbers_sorted.txt
g 1
h 1
f 2
f 2
s 4
d 5
g 5
s 5
d 9
g 10
d 29
-n
숫자 정렬을 지정합니다. -k2,2
정렬할 두 번째 열을 지정합니다.
자세한 내용은 을 참조하십시오 man sort
.
메모장을 사용하여 Unix 스크립트를 편집할 때 발생하는 문제
DOS 줄 끝으로 스크립트를 만들었습니다.
$ cat dos.sh
sort file.txt >alpha_sorted.txt
cat alpha_sorted.txt
보이지는 않지만 명령 끝에 공백을 추가했습니다 cat
. 이 파일을 사용하면 표시되는 오류를 재현할 수 있습니다.
$ chmod +x dos.sh
$ dos.sh
cat: alpha_sorted.txt: No such file or directory
: No such file or directory
dos2unix
또는 와 같은 유틸리티를 사용하여 이 문제를 해결할 수 있습니다 tr
. 사용 tr
:
$ tr -d '\r' <dos.sh >fixed.sh
$ chmod +x fixed.sh
이제 다음 명령을 성공적으로 실행할 수 있습니다.
$ fixed.sh
d 29
d 5
d 9
f 2
f 2
g 1
g 10
g 5
h 1
s 4
s 5
답변2
더 나은 정렬 방법이 있습니다.bash에서만 수행하는 대신. 이것은 귀하의 질문에 대한 좋은 대답은 아닙니다. 간단하지 않으며 (bash의 몇 가지 흔하지 않은 기능을 사용하기 때문에) 사전 빌드된 작업을 수행하는 데 사용되더라도 "유닉스 방식"으로 작업을 수행하지 않습니다. 어떤 일을 하고 그것을 잘 수행하십시오(예: 정렬).
귀하 계정의 기본 셸이 명령 실행 및 I/O 리디렉션을 위해 구축되었음을 명확히 하기 위해 이 답변을 작성하기로 결정했습니다. 껍질이 있다는 이유만으로Bash와 같은 다양한 기능특정 작업에 가장 적합한 도구라는 의미는 아닙니다. 시도하는 대신 awk 또는 perl(또는 jq 또는 sort...)을 사용하도록 제안하는 답변을 여기에서 자주 볼 수 있습니다.쉘 스크립트로 해킹하세요.
그러고보니, bash할 수 있는정렬 - 내장되어 있지 않습니다. 다시 말씀드리지만 이는 아직 좋은 생각이 아닙니다. 하지만 당신은 할 수 있습니다. 다음은 bash에 구현된 네 가지 기능입니다.유형두 필드 각각에는 두 가지 방법이 있습니다.
이러한 기능은 다음을 사용합니다.
- 정렬
- 지역 함수 변수
- 지도 파일
for ((
주기- 복잡한매개변수 대체
- 배쉬의
[[
테스트 연산자실제 정렬을 위해 - 두 값을 구문 분석하기 위한 bash의
[[
테스트 연산자 - 배쉬의
read
내장
삽입 정렬이 효율적이지 않습니다(O(n) 2), 그러나 11줄 예제와 같은 작은 데이터 세트에는 확실히 합리적입니다. 샘플 데이터의 경우 4개 함수가 1초 미만으로 실행되었지만 무작위로 생성된 1,000줄 입력 파일의 경우 "단일 배열" 정렬은 약 15초가 걸렸고 "내부" 버전은 약 60초가 걸렸습니다. 재처리. 이것을 비교하다표준 정렬 유틸리티1000분의 1초 안에 모든 열의 1,000줄 파일을 정렬합니다.
이 두 개의 "in-place" 함수는 배열(그리고 값을 반복하고 교환하기 위한 일부 일회성 변수)만 생성하여 일부 바이트를 절약하려고 시도하며 깔끔한 bash 함수를 사용하여 파일을 변환합니다. 배열로. "키잉" 기능은 바람에 주의를 기울이고둘정렬에 필요한 키용 배열과 실제 값용 배열을 분리합니다.
function sort_inplace_f1 {
local array
mapfile -t array < "$1"
local i j tmp
for ((i=0; i <= ${#array[@]} - 2; i++))
do
for ((j=i + 1; j <= ${#array[@]} - 1; j++))
do
local ivalue jvalue
[[ ${array[i]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
ivalue="${BASH_REMATCH[1]}"
[[ ${array[j]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
jvalue=${BASH_REMATCH[1]}
if [[ $ivalue > $jvalue ]]
then
tmp=${array[i]}
array[i]=${array[j]}
array[j]=$tmp
fi
done
done
printf "%s\n" "${array[@]}"
}
function sort_inplace_f2 {
local array
mapfile -t array < "$1"
local i j tmp
for ((i=0; i <= ${#array[@]} - 2; i++))
do
for ((j=i + 1; j <= ${#array[@]} - 1; j++))
do
local ivalue jvalue
[[ ${array[i]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
ivalue="${BASH_REMATCH[2]}"
[[ ${array[j]} =~ ([^[:space:]]+)[[:space:]]+(.*) ]]
jvalue=${BASH_REMATCH[2]}
if [[ $ivalue > $jvalue ]]
then
tmp=${array[i]}
array[i]=${array[j]}
array[j]=$tmp
fi
done
done
printf "%s\n" "${array[@]}"
}
function sort_keyed_f1 {
local c1 c2 keys values
while IFS=' ' read -r c1 c2
do
keys+=("$c1")
values+=("$c1 $c2")
done < "$1"
local i j tmpk tmpv
for ((i=0; i <= ${#keys[@]} - 2; i++))
do
for ((j=i + 1; j <= ${#keys[@]} - 1; j++))
do
if [[ ${keys[i]} > ${keys[j]} ]]
then
# swap keys
tmpk=${keys[i]}
keys[i]=${keys[j]}
keys[j]=$tmpk
# swap values
tmpv=${values[i]}
values[i]=${values[j]}
values[j]=$tmpv
fi
done
done
printf "%s\n" "${values[@]}"
}
function sort_keyed_f2 {
local c1 c2 keys values
while IFS=' ' read -r c1 c2
do
keys+=("$c2")
values+=("$c1 $c2")
done < "$1"
local i j tmpk tmpv
for ((i=0; i <= ${#keys[@]} - 2; i++))
do
for ((j=i + 1; j <= ${#keys[@]} - 1; j++))
do
if [[ ${keys[i]} -gt ${keys[j]} ]]
then
# swap keys
tmpk=${keys[i]}
keys[i]=${keys[j]}
keys[j]=$tmpk
# swap values
tmpv=${values[i]}
values[i]=${values[j]}
values[j]=$tmpv
fi
done
done
printf "%s\n" "${values[@]}"
}
이 모든 일이 있은 뒤에도 당신은아직셸의 핵심 "기능" 중 하나, 즉 출력을 파일로 리디렉션하는 것이 필요합니다.
sort_keyed_f1 input-file > alpha_sorted.txt
sort_keyed_f2 input-file > numbers_sorted.txt