更新(获取 20% 的行):

更新(获取 20% 的行):

例如,我们有 N 个文件(file1, file2, file3 ...)

我们需要其中的前 20%,结果目录应该类似于 (file1_20, file2_20, file3_20 ...)。

我想用它wc来获取文件的行数,然后乘以 0.2

然后使用head获取 20%,然后重定向到一个新文件,但我不知道如何自动化它。

答案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

然而,我们得到了一个浮点数,所以让我们将它转​​换为整数headdd这里也可以工作):

root@crunchbang-ibm3:~# printf %.0f "58.8" 
59

最后是 file1 的前百分之二十(给出或取一个字节):

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我们可以有效地从 进行舍入.5,但是如果文件只有 1 或 2 行长,它将错过它们。因此,我们不仅要向上舍入,而且要默认至少抓取 1 行。

答案2

当当。我用一种复杂的解析存档的方法写了整个大答案tar- 这很酷。但到了最后,我发现这一切都没有必要。您所需要的sed只是一点 shell 数学:

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它,然后 - 在 shell 的一点帮助下 - 编写自己的脚本。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 write 命令在换行符上分隔文件名参数。如果有必要的ln话,如果您需要的话,这种情况很容易解决。

w我还应该提到, rite 文件描述符的数量是有限制的sed我还应该提到,单个脚本中可以支持的。这规格说:

[sed是必须的]支持至少十个不同的w文件,与许多实现的历史实践相匹配。鼓励实施支持更多但符合要求的应用程序不应超过这个限制。

因此,上面写的命令应该可以移植到任何 POSIX 系统,最多可支持 10 个并发读/写文件。如果这种事情被合并到已发布的脚本或应用程序中,其中可能需要更多内容,那么在处理/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在大约一秒钟sed内停止在 4093 个并发打开w文件上,但这可能是我的系统的最大值,并且也可能受到影响ulimit。当它完成时 - 因为$i每次尝试都会检查 doubles 的值 -$_i被留在 2560 和$i5120。我默认在循环关闭时设置$MAXw$_i上面更安全的值 - 主要是因为我不确定是否所有seds 都会正确设置它们的返回值如果他们无法打开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在第一个输出行之前插入分隔符字符串。重要的是sedseq所有人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:使用or
获取行或字节1的百分比,其中 由给出, 其中由或给出, 最后将输出写入相应的. head -n perc filehead -c perc file
perc(( count / 5 ))
countwc -l < filewc -c < file
file_20

注意:/运算符向下舍入到最接近的整数,因此任何file*具有行/字节count < 5(因此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

相关内容