Awk 在第一行前面加上a#,因为它还没有#

Awk 在第一行前面加上a#,因为它还没有#,awk,sed,Awk,Sed,我有一个文件,其中包含我运行的命令的选项。无论何时运行该命令,我都希望它使用第一行中定义的选项运行,该选项未被注释掉。我使用以下bash脚本执行此操作: while read run opt c; do [[ $run == \#* ]] && continue ./submit.py $opt $run -c "$c" break done < to_submit.txt 在使用最后一行未注释掉的选项运行提交脚本之后,我希望在命令成功运行后注释掉该行 我可以

我有一个文件,其中包含我运行的命令的选项。无论何时运行该命令,我都希望它使用第一行中定义的选项运行,该选项未被注释掉。我使用以下bash脚本执行此操作:

while read run opt c; do
  [[ $run == \#* ]] && continue
  ./submit.py $opt $run -c "$c"
  break
done < to_submit.txt
在使用最后一行未注释掉的选项运行提交脚本之后,我希望在命令成功运行后注释掉该行

我可以找到用于将其添加到while循环的选项的行号:

line=$(grep -n "$run" to_submit.txt | grep "$opt" | grep "$c" | cut -f 1 -d ":")

但我不知道现在该如何为这一行预先准备好。我可能会使用head和tail来保存其他行,并分别处理该行,然后将其全部合并回文件中。但这听起来太复杂了,一定有一个更简单的sed或awk解决方案。

在四处搜索后,我发现

awk -v run="$run" -v opt="$opt" '{if($1 == run && $2 == opt) {print "#" $0} else print}' to_submit.txt > temp
mv -b -f temp to_submit.txt

似乎可以解决这个问题(无需先找到行号,只需比较$run和$opt)。这假设run和opt的组合足以识别一行,并且不需要注释(在我的例子中正好如此)。不确定在awk中跨越多个字段的注释将如何被考虑。

在搜索了一番之后,我发现

awk -v run="$run" -v opt="$opt" '{if($1 == run && $2 == opt) {print "#" $0} else print}' to_submit.txt > temp
mv -b -f temp to_submit.txt
$ awk '!f && sub(/^[^#]/,"#&"){f=1} 1' file
#167993 options/optionfile.py long description
#167995 options/other_optionfile.py other long description
...
似乎可以解决这个问题(无需先找到行号,只需比较$run和$opt)。这假设run和opt的组合足以识别一行,并且不需要注释(在我的例子中正好如此)。不确定在awk中跨越多个字段的注释将如何被考虑在内

$ awk '!f && sub(/^[^#]/,"#&"){f=1} 1' file
#167993 options/optionfile.py long description
#167995 options/other_optionfile.py other long description
...
要覆盖原始文件的内容,请执行以下操作:

awk '!f && sub(/^[^#]/,"#&"){f=1} 1' file > tmp && mv tmp file
与任何其他UNIX命令一样

要覆盖原始文件的内容,请执行以下操作:

awk '!f && sub(/^[^#]/,"#&"){f=1} 1' file > tmp && mv tmp file

与任何其他UNIX命令一样。

如果输入/输出文件不是很大,您可以在Bash中完成这一切:

optsfile=to_submit.txt

has_run_cmd=0
outputlines=()
while IFS= read -r inputline || [[ -n $inputline ]] ; do
    read run opt c <<<"$inputline"
    if (( has_run_cmd )) || [[ $run == \#* ]] ; then
        outputlines+=( "$inputline" )
    elif ./submit.py "$opt" "$run" -c "$c" ; then
        has_run_cmd=1
        outputlines+=( "#$inputline" )
    else
        exit $?
    fi
done < "$optsfile"

(( has_run_cmd )) && printf '%s\n' "${outputlines[@]}" > "$optsfile"
optsfile=to_submit.txt
已运行\u cmd=0
输出线=()
而IFS=read-r inputline | |[[-n$inputline]];做

read run opt c如果输入/输出文件不是很大,您可以在Bash中完成这一切:

optsfile=to_submit.txt

has_run_cmd=0
outputlines=()
while IFS= read -r inputline || [[ -n $inputline ]] ; do
    read run opt c <<<"$inputline"
    if (( has_run_cmd )) || [[ $run == \#* ]] ; then
        outputlines+=( "$inputline" )
    elif ./submit.py "$opt" "$run" -c "$c" ; then
        has_run_cmd=1
        outputlines+=( "#$inputline" )
    else
        exit $?
    fi
done < "$optsfile"

(( has_run_cmd )) && printf '%s\n' "${outputlines[@]}" > "$optsfile"
optsfile=to_submit.txt
已运行\u cmd=0
输出线=()
而IFS=read-r inputline | |[[-n$inputline]];做
在这里,使用GNU
sed
读取并运行opt c可能是最简单的:

sed '0,/^[^#]/ s//#&/' file
如果要就地更新
文件,请添加选项
-i

  • '0,/^[^#]/
    匹配第一行以外的所有行,包括第一行,该行不以
    .
    开头
  • s//#&/
    然后在该行前面加上
    • 请注意,
      s/…/
      (即,空正则表达式)重用范围中最后一个匹配的正则表达式,在本例中为
      /^[^#]/
请注意,不幸的是,该命令不适用于BSD/OSX
sed
,因为这里也不支持使用
0
启动范围以允许范围端点与第一行匹配。可以使命令与BSD/OSX
sed
一起工作,但它更麻烦。

在这里使用GNU
sed
可能是最简单的:

sed '0,/^[^#]/ s//#&/' file
如果要就地更新
文件,请添加选项
-i

  • '0,/^[^#]/
    匹配第一行以外的所有行,包括第一行,该行不以
    .
    开头
  • s//#&/
    然后在该行前面加上
    • 请注意,
      s/…/
      (即,空正则表达式)重用范围中最后一个匹配的正则表达式,在本例中为
      /^[^#]/

请注意,不幸的是,该命令不适用于BSD/OSX
sed
,因为这里也不支持使用
0
启动范围以允许范围端点与第一行匹配。可以使命令与BSD/OSX
sed
一起工作,但它更麻烦。

不能保证
cat to_submit.txt
会在
tee to_submit.txt
截断它之前读取其输入的全部内容。最好将输出写入一个临时文件,然后在替换成功后将该文件重命名为原始输入。千万不要因为@chepner声明的原因而写入正在读取的文件。也要避免UOOC(谷歌it)。是的,我刚刚通过擦除整个文件发现了这一点。。。幸好我有备份。使用临时文件编辑,不使用cat。不能保证
cat to_submit.txt
会在
tee to_submit.txt
截断之前读取其输入的全部内容。最好将输出写入一个临时文件,然后在替换成功后将该文件重命名为原始输入。千万不要因为@chepner声明的原因而写入正在读取的文件。也要避免UOOC(谷歌it)。是的,我刚刚通过擦除整个文件发现了这一点。。。幸好我有备份。使用临时文件编辑,不使用cat。我知道一定有一些sed fu可以做到这一点。它看起来也比Ed中的awk单行线更具可读性。是的,它比
awk
答案更直接地表达了意图,但表达式所采用的形式和隐含应用的规则对于新手来说可能仍然是模糊的。最终使用了此解决方案。是的,但再次,几乎所有的sed在我看来都像是魔法:)@Graipher-为了避免魔法符文,这里是关于sed的所有你需要了解的:
sed-n's/regexp/string/gp'
。对于其他任何事情,只需使用awk。有时候,sed解决方案会更简洁,甚至看起来更清晰,但不值得为这几个案例操心,因为它可能不可移植(如本例中所示),并且肯定不会随着需求的变化而扩展,等等。只要确保您理解sed命令s、g和p(带-n)阅读Arnold Robbins的《有效的Awk编程》第四版,学习如何做其他事情。我知道一定有一些sed fu可以做到这一点。