예를 들어 N개의 파일(file1, file2, file3...)이 있습니다.
그 중 처음 20%가 필요하며, 결과 디렉터리는 (file1_20, file2_20, file3_20...)과 같아야 합니다.
wc
이것을 사용하여 파일의 줄 수를 구한 다음 0.2를 곱하고 싶습니다 .
그런 다음 get 20%를 사용한 head
다음 새 파일로 리디렉션하지만 자동화하는 방법을 모르겠습니다.
답변1
따라서 작동하는 예제를 작성하십시오.
root@crunchbang-ibm3:~# echo {0..100} > file1
root@crunchbang-ibm3:~# cat file1
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
다음 명령을 사용하여 파일 크기를 바이트 단위로 얻을 수 있습니다 stat
.
root@crunchbang-ibm3:~# stat --printf %s "file1"
294
그런 다음 다음을 사용하여 bc
크기에 0.2를 곱할 수 있습니다.
root@crunchbang-ibm3:~# echo "294*.2" | bc
58.8
그러나 부동 소수점을 얻었으므로 이를 정수로 변환해 보겠습니다 head
( dd
이 방법도 작동합니다).
root@crunchbang-ibm3:~# printf %.0f "58.8"
59
마지막으로 file1의 처음 20%(바이트 제공 또는 가져오기):
root@crunchbang-ibm3:~# head -c "59" "file1"
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
그것들을 합치면 다음과 같은 일을 할 수 있습니다
mkdir -p a_new_directory
for f in file*; do
file_size=$(stat --printf %s "$f")
percent_size_as_float=$(echo "$file_size*.2" | bc)
float_to_int=$(printf %.0f "$percent_size_as_float")
grab_twenty=$(head -c "$float_to_int" "$f")
new_fn=$(printf "%s_20" "$f") # new name file1_20
printf "$grab_twenty" > a_new_directory/$new_fn
done
f
for 루프가 실행되는 디렉터리에서 발견된 항목에 대한 자리 표시자는 어디에 있습니까?file*
마친 후:
root@crunchbang-ibm3:~# cat a_new_directory/file1_20
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
업데이트(행의 20% 가져오기):
행의 처음 20% 정도를 얻으려면 다음 stat --printf %s "$f"
으로 바꿀 수 있습니다.
wc -l < "$f"
를 사용하고 있으므로 printf
효과적으로 bc
from 을 반올림할 수 있지만 .5
파일 길이가 1~2줄에 불과하면 누락됩니다. 따라서 반올림해야 할 뿐만 아니라 기본적으로 최소한 1개의 행을 가져와야 합니다.
답변2
댕댕. 나는 아카이브를 구문 분석하는 복잡한 방법을 사용하여 전체 답변을 작성했습니다 tar
. 이는 매우 멋진 일입니다. 하지만 결국 나는 이 중 어느 것도 필요하지 않다는 것을 깨달았습니다. 필요한 것은 sed
약간의 쉘 수학입니다.
set ./file[1-5];i=1 n=;eval "${n:=
} sed -n \"$(grep -c '.\|' "$@"|
sed 's|\(.*\):\(.*\)|\
$i,$(((\2/5)+(i+=\2)-\2))w \1|
')\" <<!$n"'$(cat "$@")'"$n!$n"
어떤 파일에서든 grep -c
줄 수를 와일드카드로 지정하고(나는 와일드카드로 file[1-5]
) 개수를 지정한 sed
다음, 쉘의 약간의 도움을 받아 자신만의 스크립트를 작성합니다. cat
여기 문서를 통해 입력을 제공하세요. 이는 파일을 읽으려고 하는 동안 sed
파일 중 하나를 열고 쓰기 시작 하면 어떤 일이 일어날지 확신할 수 없기 때문입니다 cat
. 그리고 크기에 따라 파이프보다 버퍼를 처리하는 것이 조금 더 나을 것이라고 생각합니다. 하지만 나는 그것에 대해 너무 명확하지 않습니다.
이를 통해 단일 스트림의 모든 파일을 읽고 w
이에 따라 출력을 작성할 수 있습니다. 파일 번호를 적절하게 늘리려면 몇 가지 설정이 필요하므로 두려워할 필요가 없습니다 grep
. 다음은 수행 중인 작업을 보여주는 eval
몇 가지 출력입니다 .set -x
+ set ./file1 ./file2 ./file3 ./file4 ./file5
+ i=1 n=
+ + grep -c .\| ./file1 ./file2 ./file3 ./file4 ./file5
sed s|\(.*\):\(.*\)|\
$i,$(((\2/5)+(i+=\2)-\2))w \1|
+ eval
sed -n "
$i,$(((18400/5)+(i+=18400)-18400))w ./file1
$i,$(((18411/5)+(i+=18411)-18411))w ./file2
$i,$(((18415/5)+(i+=18415)-18415))w ./file3
$i,$(((18418/5)+(i+=18418)-18418))w ./file4
$i,$(((18421/5)+(i+=18421)-18421))w ./file5" <<!
$(cat "$@")
!
+ cat ./file1 ./file2 ./file3 ./file4 ./file5
+ sed -n
1,3681w ./file1
18401,22083w ./file2
36812,40495w ./file3
55227,58910w ./file4
73645,77329w ./file5
보시다시피, 행은 스트림의 각 파일 위치에 따라 주소가 지정되고 w
해당 파일 이름을 읽을 때 작성됩니다. 그러나 중요한 점은 경로 이름에서 이식할 수 없는 문자를 처리하려고 시도하지 않는다는 것입니다. 특히 이 경우 sed
w
rite 명령이 줄 바꿈에서 파일 이름 인수를 구분하기 때문에 경로 이름에 새 줄을 사용할 수 없습니다. 필요한 경우 ln
필요한 경우 이 상황을 쉽게 해결할 수 있습니다.
w
sed
또한 단일 스크립트 내에서 지원될 수 있는 rite 파일 설명자 수에는 제한이 있다는 점을 언급하고 싶습니다 . 이것사양에 따르면:
[
sed
필수]w
많은 구현의 역사적 관행과 일치하는 최소 10개의 서로 다른 파일이 지원됩니다. 추가이지만 규정을 준수하는 애플리케이션을 지원하도록 구현하는 것이 좋습니다.초과해서는 안 된다이 제한.
따라서 위에 작성된 명령은 최대 10개의 동시 읽기/쓰기 파일을 지원하여 모든 POSIX 시스템으로 이식 가능해야 합니다. 이러한 종류의 내용이 더 많은 콘텐츠가 필요할 수 있는 게시된 스크립트나 애플리케이션에 통합된 경우 다음과 같이 미리 처리됩니다 /tmp
.
: & set '"" "" "" "" "" "" "" "" "" "" ';n='
' f=/tmp/$$$!'_$((i+=1))' MAXw=[num]
while eval "set '$1$1' $1;exec <<!$n\$(((i=0)+\$#))$n!$n
i=\$(sed \"$(IFS=\ ;printf "\nw $f%.0s" $1)\")"
[ "$(($#==i?(_i=i-1):(MAXw=_i)))" -lt "$MAXw" ]
do :;done; rm "/tmp/$$$!"*; unset _i i f n
sed
...이것은 현장에서 상당히 이식 가능한 역량 측정 기준이어야 합니다 . GNU는 약 1초 만에 sed
4093개의 동시에 열린 파일에서 멈춥니다 w
. 하지만 이는 아마도 내 시스템의 최대값일 것이며 영향을 받을 수도 있습니다 ulimit
. 완료되면 $i
시도할 때마다 doubles 값이 확인되므로 2560과 5120 $_i
에 남습니다 . $i
루프가 닫힐 때 위의 더 안전한 값을 기본적 $MAXw
으로 사용합니다. 주로 파일을 열 수 없는 경우 모든 s가 반환 값을 올바르게 설정할지 확신할 수 없기 때문입니다 . 하지만 독자는 이를 사용하여 원하는 작업을 수행할 수 있습니다.$_i
sed
w
의 초기 [num]
값 은 $MAXw
실제 숫자(원하는 최대 w
파일 수가 무엇이든)이어야 하며 리터럴 숫자가 아니어야 합니다 [num]
.
여기에 있는 문서화에 관해 다시 한 번 말씀드리지만, 제 생각에는 이 경우에는 그와 유사한 것이 좋은 생각입니다. sed
읽는 동안 쓰기 설명자가 유지되어야 하므로 동일한 입력/출력 이름으로 무엇을 할 수 있는지는 알 수 없습니다. 그러나 쉽게 사용할 수 있는 대안이 있는 경우에는 취할 가치가 있는 기회가 아니라고 생각합니다.
내 테스트 파일은 다음과 같이 생성됩니다.
for n in 1 2 3 4 5
do : & seq -s "$(printf "%015s--$n--%015s\n\t")" "$!" >"file$n"
done
...폐기된 프로세스 PID의 커널에서 상당히 연속적인 의사 난수를 얻습니다. 파일 내용은 분할의 불일치를 나타내도록 의도적으로 설계되었습니다. 샘플 세트의 전후 모습은 다음과 같습니다.
앞으로:
for f in file[1-5]; do
nl -ba "$f" | sed -n '$p;$=;1,3p
'; done
1 1 --1--
2 2 --1--
3 3 --1--
3681 3681 --1--
3681
1 1 --2--
2 2 --2--
3 3 --2--
3683 3683 --2--
3683
1 1 --3--
2 2 --3--
3 3 --3--
3684 3684 --3--
3684
1 1 --4--
2 2 --4--
3 3 --4--
3684 3684 --4--
3684
1 1 --5--
2 2 --5--
3 3 --5--
3685 3685 --5--
3685
형식이 조금 이상해 보인다면 첫 번째 출력 행 앞에 구분 기호 문자열이 삽입 seq
되지 않았기 때문일 수 있습니다. -s
중요한 것은 sed
모두 seq
가 nl
줄 번호에 동의하는 것 같습니다. 그래도...
뒤쪽에: ...
sed -n
1,737w ./file1
3682,4418w ./file2
7365,8101w ./file3
11049,11785w ./file4
14733,15470w ./file5
...
1 1 --1--
2 2 --1--
3 3 --1--
737 737 --1--
737
1 1 --2--
2 2 --2--
3 3 --2--
737 737 --2--
737
1 1 --3--
2 2 --3--
3 3 --3--
737 737 --3--
737
1 1 --4--
2 2 --4--
3 3 --4--
737 737 --4--
737
1 1 --5--
2 2 --5--
3 3 --5--
738 738 --5--
738
그게 바로 간단하고 효율적인 스트리밍입니다.
답변3
언급한 도구를 사용하십시오. + find
: 또는을 사용하여 라인 또는 바이트 1
의 백분율을 얻으십시오. 여기서는 또는에 의해 제공되며 마지막으로 해당 에 출력을 씁니다. head -n perc file
head -c perc file
perc
(( count / 5 ))
count
wc -l < file
wc -c < file
file_20
참고: /
연산자는 가장 가까운 정수로 반올림하므로 file*
행/바이트 count < 5
(so perc = 0
)가 있는 모든 파일은 빈 파일을 생성합니다 file*_20
.
상위 20% 가져오기 - 행:
mkdir some_dir_name
find . -maxdepth 1 -iname 'file*' -exec sh -c 'head -n $(( $(wc -l < "$0") / 5 )) "$0" > some_dir_name/"$0"_20' {} \;
처음 20%를 가져옵니다 - 바이트:
mkdir some_dir_name
find . -maxdepth 1 -iname 'file*' -exec sh -c 'head -c $(( $(wc -c < "$0") / 5 )) "$0" > some_dir_name/"$0"_20' {} \;
1텍스트 레이아웃에 따라 두 가지 방법은 예를 들어 10줄의 텍스트 예에서 상당히 다른 결과를 생성할 수 있습니다 .
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.
Abstract
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum...
총 행의 처음 20% = 처음 2개 행:
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua.
총 바이트의 처음 20% = 첫 번째 줄(잘림):
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do