ChatGPT解决这个技术问题 Extra ChatGPT

如何从 Unix 上的文本文件中提取预定范围的行?

我有一个约 23000 行的 SQL 转储,其中包含几个数据库的数据。我需要提取该文件的某个部分(即单个数据库的数据)并将其放在一个新文件中。我知道我想要的数据的开始行号和结束行号。

有谁知道一个 Unix 命令(或一系列命令)从一个文件中提取所有行,比如 16224 和 16482 行,然后将它们重定向到一个新文件中?

由于您提到大文件,我建议检查评论 stackoverflow.com/questions/83329/…

a
avandeursen
sed -n '16224,16482p;16483q' filename > newfile

sed manual

p - 打印出模式空间(到标准输出)。此命令通常仅与 -n 命令行选项一起使用。 n - 如果未禁用自动打印,则打印模式空间,然后无论如何用下一行输入替换模式空间。如果没有更多输入,则 sed 退出,不再处理任何命令。 q - 退出 sed 而不处理任何更多的命令或输入。请注意,如果未使用 -n 选项禁用自动打印,则会打印当前模式空间。

and

sed 脚本中的地址可以是以下任何一种形式: number 指定行号将仅匹配输入中的该行。可以通过指定用逗号 (,) 分隔的两个地址来指定地址范围。地址范围匹配从第一个地址匹配的位置开始的行,并一直持续到第二个地址匹配(包括)。


我很好奇这是否会修改原始文件。我备份了它以防万一,看来这并没有像预期的那样修改原始文件。
@AndyGroff。要就地修改文件,请使用“-i”参数。否则不会修改文件。
如果像我一样,您需要在一个非常大的文件上执行此操作,那么在下一行添加退出命令会有所帮助。然后是 sed -n '16224,16482p;16483q' filename。否则 sed 会一直扫描到最后(或者至少我的版本会这样)。
@MilesRout 人们似乎在问“为什么要投反对票?”很多时候,也许你的意思是“我不在乎”而不是“没人在乎”
@wds - 你的评论很值得一个爬到顶部的答案。它可以区分白天和黑夜。
J
JXG
sed -n '16224,16482 p' orig-data-file > new-file

其中 16224,16482 是起始行号和结束行号,包括。这是 1 索引的。 -n 禁止将输入回显为输出,这显然是您不想要的;数字表示执行以下命令的行范围;命令 p 打印出相关行。


在大文件上,上述命令将在找到所需范围后继续遍历整个文件。输出范围后,有没有办法让 sed 停止处理文件?
好吧,从 the answer here 开始,似乎可以使用 sed -n '16224,16482p;16482q' orig-data-file > new-file 来完成在范围末尾的停止。
你为什么要放一个不必要的空间,然后必须引用? (当然,制造不必要的问题并解决它们是一半计算机科学的本质,但我的意思是除此之外......)
J
Jakub Vrána

使用头/尾非常简单:

head -16482 in.sql | tail -258 > out.sql

使用 sed:

sed -n '16224,16482p' in.sql > out.sql

使用 awk:

awk 'NR>=16224&&NR<=16482' in.sql > out.sql

第二个和第三个选项都可以,但第一个比许多替代方案慢,因为它使用 2 个命令,其中 1 就足够了。它还需要计算才能为 tail 获得正确的参数。
值得注意的是,要保持与问题相同的行号,sed 命令应为 sed -n 16224,16482p' in.sql >out.sql,awk 命令应为 awk 'NR>=16224&&NR<=16482' in.sql > out.sql
同样值得知道的是,在第一个示例 head -16482 in.sql | tail -$((16482-16224)) >out.sql 的情况下,将计算留给 bash
第一个带有头部和尾部的 WAYYYY 在大文件上比 sed 版本更快,即使添加了 q-option。 head-version Instant 和 sed 版本我 Ctrl-C 在一分钟后...谢谢
也可以使用 tail -n +16224 来减少计算
u
user2593869

您可以使用“vi”,然后使用以下命令:

:16224,16482w!/tmp/some-file

或者:

cat file | head -n 16482 | tail -n 258

编辑:- 只是为了添加解释,您使用 head -n 16482 显示前 16482 行,然后使用 tail -n 258 从第一个输出中获取最后 258 行。


而不是 vi,你可以使用 ex,即 vi 减去交互式控制台的东西。
您不需要 cat 命令; head 可以直接读取文件。这比许多替代方案慢,因为它使用 2 个(如图所示 3 个)命令,其中 1 个就足够了。
@JonathanLeffler 你错了。它的速度非常快。我在几秒钟内从一个有 500k 行的 2G 文件中提取了 200k 行,大约 1G(没有 cat)。其他解决方案至少需要几分钟。此外,GNU 上最快的变体似乎是 tail -n +XXX filename | head XXX
f
fedorqui

awk 还有另一种方法:

awk 'NR==16224, NR==16482' file

如果文件很大,最好在读取最后一行后使用 exit。这样,它就不会不必要地读取以下行:

awk 'NR==16224, NR==16482-1; NR==16482 {print; exit}' file

awk 'NR==16224, NR==16482; NR==16482 {exit}' file

1+ 用于使用 print; exit 节省运行时间和资源。谢谢 !
第二个例子的轻微简化:awk 'NR==16224, NR==16482; NR==16482 {exit}' file
太好了,谢谢@RobinA.Meade!我在帖子中编辑了你的想法
J
Jonathan Leffler
perl -ne 'print if 16224..16482' file.txt > new_file.txt

@JonathanLeffler 在您的几个回复中,您写道“这比许多替代方案慢,因为它使用 2 个(如图所示 3 个)命令,其中 1 个就足够了。”请问上面的 perl oneliner 是不是您所说的“1 就足够了”和/或您是指 sed 还是 awk oneliner?哪个最快?
我的评论主要是指UUoC — Useless Use of cat。在 something 可以直接从文件中读取的地方使用 cat file | something … 应该总是比让 something 直接从文件中读取要慢,因为 cat 命令必须读取文件并将其写入管道,并且 something必须读取管道的内容并进行处理。这意味着对文件中数据的复制超出了必要的范围。这就是我断言的基础。我没有进行正式的测试,但要避免减速需要一些奇怪的东西。
可以想象,那个“奇怪的东西”可能是 splice(2)(另请参见 splice(2))。 OTOH,我不知道 Linux 上的 cat 是否使用它——您必须研究 cat 的源代码。
我注意到我的解决方案容易受到“但它读取整个文件”问题的影响。 Perl 可能会优化代码,但您必须研究生成的字节码才能知道它是否优化。但这绝对避免了 UUoC 问题。请注意,并非所有使用前导 cat 都是错误的,但使用单个文件名参数通常是错误的。使用 cat "$@" | something … 可以处理 0、1 或多个命令行参数,并将 something 的输入本地化为单个文件 — 这很重要。但 something "$@" 可能同样适用(除非 something 拼写为 tr 等)。
T
Tilman Vogel

站在boxxar的肩膀上,我喜欢这样:

sed -n '<first line>,$p;<last line>q' input

例如

sed -n '16224,$p;16482q' input

$ 表示“最后一行”,因此第一个命令使 sed 打印从第 16224 行开始的所有行,第二个命令使 sed 在打印第 16428 行之后退出。 (在 boxxar 的解决方案中为 q 范围添加 1 似乎没有必要。)

我喜欢这个变体,因为我不需要两次指定结束行号。而且我测量到使用 $ 不会对性能产生不利影响。


C
Cetra
 # print section of file based on line numbers
 sed -n '16224 ,16482p'               # method 1
 sed '16224,16482!d'                 # method 2

T
Tasos Papastylianou

试图为 head | tail 组合计算间隔的人想多了。

以下是在不计算任何内容的情况下获得“16224 -- 16482”范围的方法:

cat file | head -n +16482 | tail -n +16224

解释:

指示 head/tail 命令“分别从文件开始计算的指定行号“向上/开始”。

类似地,a - 指示它们“分别从文件末尾开始计数”(分别)指定的行号

上面显示的解决方案简单地使用 head first 来“将所有内容保持在最高数字”,然后使用 tail second 来“将所有内容从最低数字向上保持”,从而定义了我们感兴趣的范围(无需计算间隔)。


我发现用名字比用数字更容易理解;我把它写成 head -n +"$last_line" "$full_log_file" | tail -n +"$first_line" > "$cropped_log_file"
J
Jonathan Leffler
cat dump.txt | head -16224 | tail -258

应该做的伎俩。这种方法的缺点是您需要进行算术运算来确定 tail 的参数并说明您是否希望 'between' 包含结束行。


您不需要 cat 命令; head 可以直接读取文件。这比许多替代方案慢,因为它使用 2 个(如图所示 3 个)命令,其中 1 个就足够了。
@JonathanLeffler 这个答案是最容易阅读和记住的。如果你真的关心性能,你一开始就不会使用 shell。让特定工具专注于某项任务是一种很好的做法。此外,“算术”可以使用 | tail -$((16482 - 16224)) 解决。
r
rami

sed -n '16224,16482p' < dump.sql


j
jan.vdbergh

又快又脏:

head -16428 < file.in | tail -259 > file.out

可能不是最好的方法,但它应该工作。

顺便说一句:259 = 16482-16224+1。


这比许多替代方案慢,因为它使用 2 个命令,其中 1 个就足够了。
R
Robert Massaioli

我编写了一个名为 splitter 的 Haskell 程序,它正是这样做的:有一个 read through my release blog post

您可以按如下方式使用该程序:

$ cat somefile | splitter 16224-16482

这就是它的全部。您将需要 Haskell 来安装它。只是:

$ cabal install splitter

你完成了。我希望你发现这个程序很有用。


splitter 是否仅从标准输入读取?从某种意义上说,没关系; cat 命令不管它是否是多余的。使用 splitter 16224-16482 < somefile 或(如果它采用文件名参数)splitter 16224-16482 somefile
A
Ahmed Salman Tahir

甚至我们可以这样做在命令行检查:

cat filename|sed 'n1,n2!d' > abc.txt

例如:

cat foo.pl|sed '100,200!d' > abc.txt

您不需要在其中任何一个中使用 cat 命令; sed 完全能够自行读取文件,或者您可以从文件重定向标准输入。
C
Carl Blakeley

使用红宝石:

ruby -ne 'puts "#{$.}: #{$_}" if $. >= 32613500 && $. <= 32614500' < GND.rdf > GND.extract.rdf

K
KevinY

我想从使用变量的脚本中做同样的事情,并通过在 $variable 周围加上引号以将变量名称与 p 分开来实现它:

sed -n "$first","$count"p imagelist.txt >"$imageblock"

我想将列表拆分为单独的文件夹,并发现最初的问题和答案是一个有用的步骤。 (拆分命令不是我必须将代码移植到的旧操作系统的选项)。


A
Anselmo Blanco Dominguez

只需对上面给出的 3 个解决方案进行基准测试,这对我有用:

awk

sed

“头+尾”

3 个解决方案的学分归于:

@boxxar

@avandeursen

@wds

@manveru

@sibaz

@SOFe

@fedorqui '停止伤害'

@Robin A.米德

我正在使用在我的服务器中找到的一个大文件:

# wc fo2debug.1.log
   10421186    19448208 38795491134 fo2debug.1.log

38 Gb,1040 万行。

是的,我有一个 logrotate 问题。 :))

让你的赌注!

从文件开头获取 256 行。

# time sed -n '1001,1256p;1256q' fo2debug.1.log | wc -l
256

real    0m0,003s
user    0m0,000s
sys     0m0,004s

# time head -1256 fo2debug.1.log | tail -n +1001 | wc -l
256

real    0m0,003s
user    0m0,006s
sys     0m0,000s

# time awk 'NR==1001, NR==1256; NR==1256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,002s
user    0m0,004s
sys     0m0,000s

奥克赢了。 sed 和“head+tail”在技术上并列第二。

在文件的前三分之一末尾获得 256 行。

# time sed -n '3473001,3473256p;3473256q' fo2debug.1.log | wc -l
256

real    0m0,265s
user    0m0,242s
sys     0m0,024s

# time head -3473256 fo2debug.1.log | tail -n +3473001 | wc -l
256

real    0m0,308s
user    0m0,313s
sys     0m0,145s

# time awk 'NR==3473001, NR==3473256; NR==3473256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,393s
user    0m0,326s
sys     0m0,068s

赛德赢了。接着是“头+尾”,最后是 awk。

在文件的第二个三分之一的末尾获得 256 行。

# time sed -n '6947001,6947256p;6947256q' fo2debug.1.log | wc -l
A256

real    0m0,525s
user    0m0,462s
sys     0m0,064s

# time head -6947256 fo2debug.1.log | tail -n +6947001 | wc -l
256

real    0m0,615s
user    0m0,488s
sys     0m0,423s

# time awk 'NR==6947001, NR==6947256; NR==6947256 {exit}' fo2debug.1.log | wc -l
256

real    0m0,779s
user    0m0,650s
sys     0m0,130s

结果相同。

赛德赢了。接着是“头+尾”,最后是 awk。

在文件末尾附近获得 256 行。

# time sed -n '10420001,10420256p;10420256q' fo2debug.1.log | wc -l
256

real    1m50,017s
user    0m12,735s
sys     0m22,926s

# time head -10420256 fo2debug.1.log | tail -n +10420001 | wc -l
256

real    1m48,269s
user    0m42,404s
sys     0m51,015s

# time awk 'NR==10420001, NR==10420256; NR==10420256 {exit}' fo2debug.1.log | wc -l
256

real    1m49,106s
user    0m12,322s
sys     0m18,576s

突然,一个转折!

“头+尾”赢了。接着是 awk,最后是 sed。

(几个小时后……)

对不起大家!

我上面的分析最终成为分析中基本缺陷的一个例子。

缺陷在于不深入了解用于分析的资源。

在这种情况下,我使用了一个日志文件来分析在其中搜索一定数量的行的性能。

使用 3 种不同的技术,在文件中的不同点进行搜索,比较技术在每个点的性能,并检查结果是否因文件中进行搜索的点而异。

我的错误是假设日志文件中的内容具有一定的同质性。

现实情况是,长行出现在文件末尾的频率更高。

因此,用给定的技术,更长的搜索(更接近文件的末尾)更好的明显结论可能是有偏见的。事实上,这种技术在处理较长的行时可能会更好。什么还有待确认。


g
guerda

我正要发布头/尾技巧,但实际上我可能只是启动了 emacs。 ;-)

esc-x goto-line ret 16224 mark (ctrl-space) esc-x goto-line ret 16482 esc-w

打开新的输出文件,ctl-y保存

让我看看发生了什么。


根据我的经验,Emacs 在非常大的文件上表现不佳。
您可以将其作为脚本操作运行,还是只是一个交互式选项?
P
Paddy3118

我会使用:

awk 'FNR >= 16224 && FNR <= 16482' my_file > extracted.txt

FNR 包含从文件中读取的行的记录(行)号。


B
Benjamin W.

使用编辑:

ed -s infile <<<'16224,16482p'

-s 抑制诊断输出;实际命令位于此处的字符串中。具体来说,16224,16482p 在所需的行地址范围内运行 p(打印)命令。


D
DrNerdfighter

我写了一个小 bash 脚本,你可以从命令行运行它,只要你更新你的 PATH 以包含它的目录(或者你可以把它放在一个已经包含在 PATH 中的目录中)。

用法:$ pinch filename start-line end-line

#!/bin/bash
# Display line number ranges of a file to the terminal.
# Usage: $ pinch filename start-line end-line
# By Evan J. Coon

FILENAME=$1
START=$2
END=$3

ERROR="[PINCH ERROR]"

# Check that the number of arguments is 3
if [ $# -lt 3 ]; then
    echo "$ERROR Need three arguments: Filename Start-line End-line"
    exit 1
fi

# Check that the file exists.
if [ ! -f "$FILENAME" ]; then
    echo -e "$ERROR File does not exist. \n\t$FILENAME"
    exit 1
fi

# Check that start-line is not greater than end-line
if [ "$START" -gt "$END" ]; then
    echo -e "$ERROR Start line is greater than End line."
    exit 1
fi

# Check that start-line is positive.
if [ "$START" -lt 0 ]; then
    echo -e "$ERROR Start line is less than 0."
    exit 1
fi

# Check that end-line is positive.
if [ "$END" -lt 0 ]; then
    echo -e "$ERROR End line is less than 0."
    exit 1
fi

NUMOFLINES=$(wc -l < "$FILENAME")

# Check that end-line is not greater than the number of lines in the file.
if [ "$END" -gt "$NUMOFLINES" ]; then
    echo -e "$ERROR End line is greater than number of lines in file."
    exit 1
fi

# The distance from the end of the file to end-line
ENDDIFF=$(( NUMOFLINES - END ))

# For larger files, this will run more quickly. If the distance from the
# end of the file to the end-line is less than the distance from the
# start of the file to the start-line, then start pinching from the
# bottom as opposed to the top.
if [ "$START" -lt "$ENDDIFF" ]; then
    < "$FILENAME" head -n $END | tail -n +$START
else
    < "$FILENAME" tail -n +$START | head -n $(( END-START+1 ))
fi

# Success
exit 0

这比许多替代方案慢,因为它使用 2 个命令,其中 1 个就足够了。事实上,它会因为 wc 命令读取文件两次,这会浪费磁盘带宽,尤其是在千兆字节文件上。在各种方面,这是有据可查的,但它也是工程矫枉过正。
喜欢“捏”这个词来描述它的作用。 :D
p
potong

这可能对您有用(GNU sed):

sed -ne '16224,16482w newfile' -e '16482q' file

或利用 bash:

sed -n $'16224,16482w newfile\n16482q' file

K
Kemin Zhou

由于我们正在讨论从文本文件中提取文本行,因此我将给出一个特殊情况,您希望提取与特定模式匹配的所有行。

myfile content:
=====================
line1 not needed
line2 also discarded
[Data]
first data line
second data line
=====================
sed -n '/Data/,$p' myfile

将打印 [Data] 行和剩余部分。如果您想要从 line1 到模式的文本,请键入:sed -n '1,/Data/p' myfile。此外,如果您知道两个模式(最好在您的文本中是唯一的),则可以使用匹配项指定范围的开始行和结束行。

sed -n '/BEGIN_MARK/,/END_MARK/p' myfile

f
fedorqui

接受答案中的 -n 有效。如果您愿意,这是另一种方式。

cat $filename | sed "${linenum}p;d";

这将执行以下操作:

管道输入文件的内容(或根据需要输入文本)。 sed 选择给定的行,打印它 d 需要删除行,否则 sed 将假定最终将打印所有行。即,如果没有 d,您将打印两次所选行打印的所有行,因为您有 ${linenum}p 部分要求打印它。我很确定 -n 基本上和这里的 d 做同样的事情。


注意 cat file | sed 最好写成 sed file
这也只是打印一行,而问题是关于它们的范围。
K
Kahiga

我一直在寻找这个问题的答案,但我最终不得不编写自己的代码。上面的答案没有一个是令人满意的。考虑您有非常大的文件并且有某些要打印的行号,但这些数字不按顺序排列。您可以执行以下操作:

我比较大的文件for letter in {a..k} ; do echo $letter; done | cat -n > myfile.txt

 1  a
 2  b
 3  c
 4  d
 5  e
 6  f
 7  g
 8  h
 9  i
10  j
11  k

我想要的特定行号:shuf -i 1-11 -n 4 > line_numbers_I_want.txt

 10
 11
 4
 9

要打印这些行号,请执行以下操作。 awk '{system("head myfile.txt -n " $0 " | tail -n 1")}' line_numbers_I_want.txt

上面所做的是将 n 行放在前面,然后使用 tail 取最后一行

如果您希望按顺序排列行号,请先排序(是 -n 数字排序)然后获取行。

cat line_numbers_I_want.txt | sort -n | awk '{system("head myfile.txt -n " $0 " | tail -n 1")}'

 4  d
 9  i
10  j
11  k

u
user2928048

也许,你会很乐意给这个不起眼的脚本一个机会;-)

#!/usr/bin/bash

# Usage:
#   body n m|-m

from=$1
to=$2

if [ $to -gt 0 ]; then
# count $from the begin of the file $to selected line
    awk "NR >= $from && NR <= $to {print}"
else
# count $from the begin of the file skipping tailing $to lines
    awk '
    BEGIN   {lines=0; from='$from'; to='$to'}
            {++lines}
    NR >= $from {line[lines]=$0}
    END     {for (i = from; i < lines + to + 1; i++) {
                print line[i]
            }
    }'
fi

输出:

$ seq 20 | ./body.sh 5 15
5
6
7
8
9
10
11
12
13
14
15

$ seq 20 | ./body.sh 5 -5
5
6
7
8
9
10
11
12
13
14
15

R
RARE Kpop Manifesto

我为 sedperlhead+tail 编译了一些评分最高的解决方案,以及我自己的 awk 代码,并通过管道关注性能,同时使用 LC_ALL=C 确保所有候选人他们最快,在两者之间分配 2 秒的睡眠间隔。

差距有些明显:

   abs time    awk/app speed ratio
 ----------------------------------
   0.0672 sec :   1.00x mawk-2
   0.0839 sec :   1.25x gnu-sed
   0.1289 sec :   1.92x perl
   0.2151 sec :   3.20x gnu-head+tail

没有机会测试这些实用程序的 pythonBSD 变体。

 (fg && fg && fg && fg) 2>/dev/null; 
 echo;
 ( time ( pvE0 < "${m3t}" 
        | LC_ALL=C  mawk2 '

           BEGIN {  
                     _=10420001-(\
                    __=10420256)^(FS="^$") 
           } _<NR { 
                   print

                   if(__==NR) { exit } 
     
     }' ) | pvE9) | tee >(xxh128sum >&2) | LC_ALL=C gwc -lcm | lgp3 ; 
    sleep 2;
    (fg && fg && fg && fg) 2>/dev/null
    echo; 
    ( time ( pvE0 < "${m3t}" 
           | LC_ALL=C gsed -n '10420001,10420256p;10420256q' 
    
     ) | pvE9 ) |  tee >(xxh128sum >&2) |  LC_ALL=C gwc -lcm  | lgp3 ;
     sleep  2; (fg && fg && fg && fg) 2>/dev/null
     echo
    ( time ( pvE0 < "${m3t}" 
           | LC_ALL=C perl -ne 'print if 10420001..10420256'
    
    ) | pvE9 ) |  tee >(xxh128sum >&2) |  LC_ALL=C gwc -lcm | lgp3 ;
    sleep  2; (fg && fg && fg && fg) 2>/dev/null
    echo
    ( time ( pvE0 < "${m3t}" 
           | LC_ALL=C ghead -n +10420256 
           | LC_ALL=C gtail -n +10420001 
    ) | pvE9 ) |  tee >(xxh128sum >&2) |  LC_ALL=C gwc -lcm  | lgp3 ; 


      in0: 1.51GiB 0:00:00 [2.31GiB/s] [2.31GiB/s] [============> ] 81%            
     out9: 42.5KiB 0:00:00 [64.9KiB/s] [64.9KiB/s] [ <=> ]
( pvE 0.1 in0 < "${m3t}" | LC_ALL=C mawk2 ; )
     
   0.43s user 0.36s system 117% cpu 0.672 total
    256   43487   43487

54313365c2e66a48dc1dc33595716cc8  stdin

     out9: 42.5KiB 0:00:00 [51.7KiB/s] [51.7KiB/s] [ <=> ]
      in0: 1.51GiB 0:00:00 [1.84GiB/s] [1.84GiB/s] [==========> ] 81%            

   ( pvE 0.1 in0 < "${m3t}" |LC_ALL=C gsed -n '10420001,10420256p;10420256q'; )  
  
   0.68s user 0.34s system 121% cpu 0.839 total
    256   43487   43487

54313365c2e66a48dc1dc33595716cc8  stdin


      in0: 1.85GiB 0:00:01 [1.46GiB/s] [1.46GiB/s] [=============>] 100%            
     out9: 42.5KiB 0:00:01 [33.5KiB/s] [33.5KiB/s] [  <=> ]

( pvE 0.1 in0 < "${m3t}" | LC_ALL=C perl -ne 'print if 10420001..10420256'; )
     
   1.10s user 0.44s system 119% cpu 1.289 total
    256   43487   43487

54313365c2e66a48dc1dc33595716cc8  stdin

      in0: 1.51GiB 0:00:02 [ 728MiB/s] [ 728MiB/s] [=============> ] 81%            
     out9: 42.5KiB 0:00:02 [19.9KiB/s] [19.9KiB/s] [ <=> ]

 ( pvE 0.1 in0 < "${m3t}" 
   | LC_ALL=C ghead -n +10420256 
   | LC_ALL=C gtail -n ; )  
  
 1.98s user 1.40s system 157% cpu 2.151 total
 256   43487   43487

54313365c2e66a48dc1dc33595716cc8  stdin

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅