获得25%的文件行

时间:2012-10-20 12:38:52

标签: shell

我尝试随机显示25%的文件行

这是我的剧本:

file=$1
nb_lignes=$(wc -l $file | cut -d " " -f1)
num_lines_to_get=$((25*${nb_lignes}/100)) 
for (( i=0; i < $num_lines_to_get; i++))
do
line=$(head -$((${RANDOM} % $nb_lignes)) $file | tail -1)
echo "$line"
done
fi

我像那样跑

./script.sh file

文件是:

xxxxxxxx-54.yyyyy
xxxxxxxx-55.yyyyy
xxxxxxxx-60.yyyyy
xxxxxxxx-66.yyyyy

我的问题请问我怎么能消除54 55,我的意思是我喜欢这个列表的25%而不是这两行54和55,我想在命令中指定它

./script.sh file 54 55

谢谢。

2 个答案:

答案 0 :(得分:4)

除非您知道有多少行代表100%,否则无法计算25%,因此您的所有解决方案将(1)单通并将您的文件存储在内存中,或(2)按顺序多次通过收集行数。我不知道你要处理的文件有多长,但我还是更喜欢第二个选项,所以这就是我的答案。

如果您正在运行Linux,那么您可能拥有大多数工具的GNU版本。一种解决方案可能是:

#!/bin/sh

linecount=$(awk 'END{printf("%d", NR * 0.25)}' input.txt)
exclude="$@"
egrep -vw "${exclude// /|}" input.txt | shuf -n$linecount

或者:

#!/bin/sh

linecount=$(awk 'END{printf("%d", NR * 0.25)}' input.txt)
exclude="$@"
egrep -vw "${exclude// /|}" input.txt | sort -R | head -n $linecount

此解决方案假定“xxxxxx”和“yyyyy”字符串不包含您尝试跳过的数字的字分隔版本。如果他们可能,那么你应该给我们更多的细节,比如实际的样本数据。

如果您使用的是FreeBSD或OSX,那么sort没有-R选项,并且不包含shuf,但您仍然可以完成此操作。您的系统中将有一个名为jot的工具。它可用于生成范围内的随机数。所以这有点尴尬,但它确实有效:

#!/bin/sh

# `awk` is a little heaver than `wc`, but you don't need to parse its output.
lines=$(awk 'END{printf("%d", NR * 0.25)}' input.txt)

exclude="$@"

# First, put a random number at the beginning of each line.
while read line; do
  # skip lines that match our exclusion list
  if [[ $line =~ -($exclude). ]]; then
    continue
  fi
  echo "`jot -r 1 1 10000000` $line"
done < input.txt > stage1.txt

# Next, sort by the random number.
sort -n stage1.txt > stage2.txt

# Last, remove the number from the start of each line.
sed -r 's/^[0-9]+ //' stage2.txt > stage3.txt

# Show our output
head -n $lines stage3.txt

# Clean up
rm stage1.txt stage2.txt stage3.txt

如果您愿意,可以将这些行中的一些组合在一起,以避免将事物分级为单独的文件。

#!/bin/sh

lines=$(awk 'END{printf("%d", NR * 0.25)}' input.txt)

exclude="$@"

while read line; do
  if [[ $line =~ -(${exclude// /|})\. ]]; then
    continue
  fi
  echo "`jot -r 1 1 10000000` $line"
done < input.txt | sort -n | sed -r 's/^[0-9]+ //' | head -n $lines

# no clean-up required

答案 1 :(得分:2)

您可以使用一系列unix工具。 shuf是一个很好的wcawk。使用相同的方法计算线条,但随后调整要打印的行数以忽略某些线条,然后打印随机数量的线条。

num_lines=$(wc -l $file | cut -f1 -d' ' )
high=55
low=54

if [ "$num_lines" -ge $high ]; then : $((num_lines--)); fi
if [ "$num_lines" -ge $low ]; then : $((num_lines--)); fi

awk '(NR != '$low' && NR != '$high') { print }' < $file \
    | shuf -n $((num_lines / 4))

请注意,if语句的顺序很重要,因此会发生正确的减法次数(即如果文件有54行,则只应跳过一行,因此只有一行减法,如果有55行,然后将跳过两行,并且这种排序是必需的,否则第二次减法将不会发生。)

注意,如果您希望这些行按其原始顺序排列,则可以使用以下代码来代替最后一个awk .. | shuf ..管道。

awk '(NR != '$low' && NR != '$high') { print NR,$0 }' < $file \
    | shuf -n $((num_lines / 4)) | sort -n | cut -f2- -d' '

(它首先用它的行号标记每一行,然后按此排序,然后将其删除,即Schwartzian Transform。)