【问题标题】:Including awk in shell script makes the output empty?在 shell 脚本中包含 awk 会使输出为空?
【发布时间】:2016-02-16 00:35:26
【问题描述】:

我制作了一个 shell 脚本,可以用来制作 MPD 的播放列表。我可以按照我想要的那样按文件夹和艺术家写歌曲,但是当我尝试使用 awk 在脚本末尾删除重复项时,输出变为空。

脚本如下:

(
mpc search artist 'Black Coast' &&
mpc search artist 'ASTR' &&
ls ~/music/HDD/Chill | awk '$0="HDD/Chill/"$0'
) | tee testi.txt;
awk '!v[$0]++' testi.txt | tee testi.txt

上面的 awk 正确地为字符串添加了前缀,但是如果我在输出下方添加 awk,则输出是一个空文件。但是,当超出脚本文件时,该行仍然有效。

编辑:它适用于

(
mpc search artist 'Black Coast' &&
mpc search artist 'ASTR' &&
ls ~/music/HDD/Chill | awk '$0="HDD/Chill/"$0'
) | awk '!v[$0]++' | tee testi.txt

所以我的问题变成了为什么上面的例子不起作用?

【问题讨论】:

  • 为什么是两个tees?为什么你有一个临时文件?
  • 如果你有 GNU awk,你可以进行就地编辑。还有来自 moreutils 的海绵:unix.stackexchange.com/a/207921/70524

标签: bash shell awk


【解决方案1】:

您正在写入您正在阅读的同一个文件。永远不要这样做,因为 shell 可以在读取它之前编写它。你想要这样的东西(未经测试):

(awk '!v[$0]++' testi.txt | tee tmp.txt) && mv tmp.txt testi.txt

【讨论】:

  • 所以基本上是异步的?
  • idk 如果这是我选择的术语,但是当您使用相同的命令读取和写入相同的文件时,由 shell 决定读取和写入的顺序。 Google 是您的朋友...
【解决方案2】:

我想这里的问题是您的输入和输出文件是相同的。这将导致它在 awk 可以读取之前被截断以进行写入。

我建议这样做:

(
    mpc search artist 'Black Coast' &&
    mpc search artist 'ASTR' &&
    ls ~/music/HDD/Chill | awk '$0="HDD/Chill/"$0'
) | awk '!v[$0]++' | tee testi.txt

这样,输出文件只被触摸一次。

另外,我不太喜欢 ls 行的外观 - 我建议使用这样的东西:

( cd ~/music && printf '%s\n' HDD/Chill/* )

这会创建一个额外的子shell,但不需要外部子shell,因此您可以将命令更改为:

{
    mpc search artist 'Black Coast' &&
    mpc search artist 'ASTR' &&
    ( cd ~/music && printf '%s\n' HDD/Chill/* )
} | awk '!v[$0]++' | tee testi.txt

如果您的文件名包含换行符,这将失败(但同样,您的原始方法也是如此)。

【讨论】:

  • 除了更容易复制(如果我想要更多文件夹)之外,还有其他好处吗?
  • 我不太确定你所说的更容易复制是什么意思,但我想你是在问我对 printf 的使用情况。首先,避免在脚本中使用ls 是个好主意——在这种情况下,这不是什么大问题,但这是一个不好的习惯。这种方式也避免了目录名的重复。
  • 我所说的更容易复制的意思是目录名的重复。我并不关心我对 ls 的使用,但我会改用你的,只是为了避免重复,而且整体看起来更干净。
猜你喜欢
  • 1970-01-01
  • 2017-12-07
  • 1970-01-01
  • 1970-01-01
  • 2022-08-14
  • 2014-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多