我有一个调用两个命令的脚本:
long_running_command | print_progress
Run Code Online (Sandbox Code Playgroud)
在long_running_command打印的进展,但我很不满意它。我正在使用print_progress使其更好(即,我在一行中打印进度)。
问题:将管道连接到标准输出也会激活一个 4K 缓冲区,所以漂亮的打印程序什么都没有……什么都没有……什么都没有……很多……:)
如何禁用4K缓冲区long_running_command(不,我没有源)?
我从来没有真正考虑过 shell 是如何实际执行管道命令的。我一直被告知“一个程序的标准输出通过管道传输到另一个程序的标准输入中”,这是对管道的一种思考方式。所以很自然地,我认为在 say 的情况下,A | B,A将首先运行,然后B获取 的标准输出A,并使用标准输出A作为其输入。
但我注意到,当人们搜索特定的工艺ps,他们会包括grep -v "grep"在命令的末尾,以确保grep不会出现在最终的输出。
这意味着在命令ps aux | grep "bash" | grep -v "grep"中暗示ps知道grep正在运行,因此在ps. 但是如果ps在它的输出通过管道传输到 之前完成运行,它grep怎么知道它grep正在运行?
flamingtoast@FTOAST-UBUNTU: ~$ ps | grep ".*"
PID TTY TIME CMD
3773 pts/0 00:00:00 bash
3784 pts/0 00:00:00 ps
3785 pts/0 00:00:00 grep
Run Code Online (Sandbox Code Playgroud) 我知道您可以创建一个文件描述符并将输出重定向到它。例如
exec 3<> /tmp/foo # open fd 3.
echo a >&3 # write to it
exec 3>&- # close fd 3.
Run Code Online (Sandbox Code Playgroud)
但是你可以在没有文件描述符的情况下做同样的事情:
FILE=/tmp/foo
echo a > "$FILE"
Run Code Online (Sandbox Code Playgroud)
我正在寻找一个很好的例子,说明何时必须使用额外的文件描述符。
我有 200 GB 的可用磁盘空间、16 GB 的 RAM(其中约 1 GB 被桌面和内核占用)和 6 GB 的交换空间。
我有一个 240 GB 的外部 SSD,使用了 70 GB 1,其余的免费,我需要将其备份到我的磁盘。
通常,我会dd if=/dev/sdb of=Desktop/disk.img先创建磁盘,然后对其进行压缩,但是首先制作映像不是一种选择,因为这样做需要比我拥有的磁盘空间多得多的磁盘空间,即使压缩步骤会导致可用空间被压缩,因此最终存档可以很容易地放在我的磁盘上。
dd默认情况下写入 STDOUT,并且gzip可以从 STDIN 读取,所以理论上我可以写入dd if=/dev/sdb | gzip -9 -,但gzip读取字节所需的时间比dd产生它们的时间要长得多。
来自man pipe:
写入管道写端的数据由内核缓冲,直到从管道的读端读取。
我将 a 想象|成一个真正的管道——一个应用程序将数据推入,另一个应用程序尽可能快地从管道队列中取出数据。
当左侧的程序写入的数据比管道的另一侧希望处理的数据多时,该怎么办?它会导致极端的内存或交换使用,还是内核会尝试在磁盘上创建一个 FIFO,从而填满磁盘?或者SIGPIPE Broken pipe如果缓冲区太大它会失败吗?
基本上,这归结为两个问题:
注 1:我不能仅仅复制前 70 个使用的 GB 并期望获得一个工作系统或文件系统,因为碎片和其他需要完整内容完整的东西。
我想要tar一个目录并将结果写入stdout,然后将其通过管道传输到压缩程序,如下所示:
tar -cvf - /tmp/source-dir | lzip -o /media/my-usb/result.lz -
Run Code Online (Sandbox Code Playgroud)
我一直在使用管道来输出多行文本的命令。现在我想知道当我用管道输出一个(快速)命令时会发生什么,例如非常大的输出,tar然后是一个非常慢的压缩命令?会tar等待它的输出被消耗掉lzip吗?或者它只是尽可能快地将所有内容输出到RAM?如果后者属实,那么在低 RAM 系统中将是一场灾难。
假设我有一个名为 的makefile,hour_long_recipe顾名思义,它需要一个小时才能运行。在整个食谱的随机点上,它会问是/否问题。假设它总共问了 10 个问题。
一种可能(并且经常被推荐)的运行方式是:
yes | make hour_long_recipe
Run Code Online (Sandbox Code Playgroud)
用 回答所有问题y。但是,根据我的理解,无论是否实际使用来自其标准输入的数据,都会yes以高达每秒 10.2 GiB 的速度输出到标准输出make。
即使它只有 10 MiB/s(比任何yes可以相信的 reddit 线程的实现都慢得多),在一小时内它会加起来超过 35 GiB,其中只有 20 个字节将被读取。数据去哪儿了?可以将其保存到磁盘,但这很浪费,如果磁盘填满的速度足够快,它甚至可能导致make失败。
据推测,操作系统会阻止它到达那个状态,但是如何呢?什么是限制,达到该限制时会发生什么?
我有两个简单的程序:A和B.? A将首先运行,然后B获取“stdout”A并将其用作“stdin”。?假设我使用的是 GNU/Linux 操作系统,最简单的方法是:
./A | ./B
Run Code Online (Sandbox Code Playgroud)
如果我必须描述这个命令,我会说它是一个从生产者 ( A)获取输入(即读取)并写入消费者 ( B) 的命令。?这是一个正确的描述吗?我错过了什么吗?
我有一个生成文件,我在删除文件之前停止服务。当它无法停止服务时,它会因错误而中断。这显然是不需要的,所以我想我会添加|| true但错过了|. 进行中:
stop service foo | true
rm /etc/init/foo.conf
Run Code Online (Sandbox Code Playgroud)
我很困惑为什么这会起作用以及正在发生什么。这是否意味着这true是一个应用程序而不仅仅是一个关键字?他们是一样的吗?有充分的理由使用| true吗?
我想知道三通是否会减慢管道速度。毕竟,将数据写入磁盘比管道传输要慢。
tee 是否等待将数据发送到下一个管道,直到数据写入磁盘?(如果没有,我想 tee 必须将已发送但未写入磁盘的数据排队,这对我来说不太可能。)
$ program1 input.txt | tee intermediate-file.txt | program2 ...
Run Code Online (Sandbox Code Playgroud) 我在 nfs 挂载上有一个目录,它在服务器上位于 /home/myname/.rubies
Root 无法访问此目录:
[mitchell.usher@server ~]$ stat /home/mitchell.usher/.rubies
File: `/home/mitchell.usher/.rubies'
Size: 4096 Blocks: 8 IO Block: 32768 directory
Device: 15h/21d Inode: 245910 Links: 3
Access: (0755/drwxr-xr-x) Uid: ( 970/mitchell.usher) Gid: ( 100/ users)
Access: 2016-08-22 15:06:15.000000000 +0000
Modify: 2016-08-22 14:55:00.000000000 +0000
Change: 2016-08-22 14:55:00.000000000 +0000
[mitchell.usher@server ~]$ sudo !!
sudo stat /home/mitchell.usher/.rubies
stat: cannot stat `/home/mitchell.usher/.rubies': Permission denied
Run Code Online (Sandbox Code Playgroud)
我试图从该目录中复制一些/opt只有 root 有权访问的内容:
[mitchell.usher@server ~]$ cp .rubies/ruby-2.1.3/ -r /opt
cp: cannot create directory `/opt/ruby-2.1.3': Permission denied
[mitchell.usher@server ~]$ …Run Code Online (Sandbox Code Playgroud) pipe ×8
shell ×3
bash ×1
buffer ×1
compression ×1
dd ×1
file-copy ×1
gzip ×1
linux ×1
permissions ×1
ps ×1
root ×1
shell-script ×1
tee ×1
terminology ×1
yes ×1