在shell脚本中缩进多行输出

ippsafx7  于 12个月前  发布在  Shell
关注(0)|答案(6)|浏览(160)

我想在我的Ubuntu Amazon EC2盒子上更改当天的消息(MOTD),这样当我SSH进入时,它会显示我的一个目录的git状态。
所有默认MOTD文件的输出在每行的开头都有两个空格,所以它看起来缩进得很好,但是因为我的git status输出跨越了几行,如果我在echo -n " "之前执行它,它只缩进第一行。
你知道我怎么才能让它覆盖每一行吗?

wooyq4lh

wooyq4lh1#

将其通过管道连接到sed,在每行的开头插入2个空格。

git status | sed 's/^/  /'
6xfqseft

6xfqseft2#

基于@Barmar的回答,这是一种更整洁的方法:

indent() { sed 's/^/  /'; }

git status | indent
other_command | indent
iszxjhcz

iszxjhcz3#

感谢@Barmar和@Marplesoft提供了一些很好的简单解决方案-这是其他人可能会喜欢的另一种变体-一个可以使用pr判断有多少个级别的函数:

indent() {
  local indentSize=2
  local indent=1
  if [ -n "$1" ]; then indent=$1; fi
  pr -to $(($indent * $indentSize))
}

# Example usage
ls -al | indent
git status | indent 2
5jdjgkvh

5jdjgkvh4#

为了提高效率,您可以在不调用任何工具(如sed)的情况下完成此操作:

output=$(git status); echo "  ${output//$'\n'/$'\n'  }."

或者,在函数中:

indent()
{
    local unindented
    unindented="$(< /dev/stdin)"
    echo "  ${unindented//$'\n'/$'\n'  }."
}

git status | indent

工作原理:Bash参数扩展将每个“end of line”替换为“end of line”+。第一行前面没有“end of line”,所以我们在整个字符串前面加上
这节省了启动整个sed/etc进程的时间(不过,在这种情况下,输出还没有在变量中,如果文本比sed二进制文件大,分配变量可能会花费更多的时间)。
与大多数解决方案一样,原始输出中的制表符(可能看起来像8个空格)只是在前面加上2个空格,然后制表符缩小,因此它看起来仍然像是用8个空格标识的。这可能是期望的,也可能不是。

kkih6yb8

kkih6yb85#

下面是我写的一个函数,也是给dustderr的:

function indented {
  local PIPE_DIRECTORY=$(mktemp -d)
  trap "rm -rf '$PIPE_DIRECTORY'" EXIT

  mkfifo "$PIPE_DIRECTORY/stdout"
  mkfifo "$PIPE_DIRECTORY/stderr"

  "$@" >"$PIPE_DIRECTORY/stdout" 2>"$PIPE_DIRECTORY/stderr" &
  local CHILD_PID=$!

  sed 's/^/  /' "$PIPE_DIRECTORY/stdout" &
  sed 's/^/  /' "$PIPE_DIRECTORY/stderr" >&2 &
  wait "$CHILD_PID"
  rm -rf "$PIPE_DIRECTORY"
}

像这样使用它:

indented git status
indented ls -al
jutyujz0

jutyujz06#

以下函数run_indented运行传递的命令行,并使用$INDENT缩进标准输出STDOUT * 和STDERR *(默认值:``):

run_indented() {
  local indent=${INDENT:-"    "}
  { "$@" 2> >(sed "s/^/$indent/g" >&2); } | sed "s/^/$indent/g"
}

默认值示例:

run_indented bash <<'EOF'
    echo "foo" >&2
    echo "bar"
EOF

图纸:

foo
    bar

自定义和嵌套示例:

export -f run_indented

INDENT='- ' run_indented bash <<'EOF'
    echo "foo" >&2
    echo "bar"

    # The following run_indented only works if
    # it was exported as in the first line.
    run_indented bash -c '
      echo "foo2" >&2
      echo "bar2"
    '
EOF

图纸:

- bar
- foo
- - foo2
- - bar2

奖励:保留格式

有些工具会检查它们是否连接到终端,如果是这样,则只输出格式/颜色。
基于管道的缩进解决方案可能会导致缩进工具看不到端子,并且颜色消失。
如果您想保留格式,请尝试以下版本:

run_indented() {
  local indent=${INDENT:-"    "}
  local indent_cmdline=(awk '{print "'"$indent"'" $0}')

  if [ -t 1 ] && command -v unbuffer >/dev/null 2>&1; then
    { unbuffer "$@" 2> >("${indent_cmdline[@]}" >&2); } | "${indent_cmdline[@]}"
  else
    { "$@" 2> >("${indent_cmdline[@]}" >&2); } | "${indent_cmdline[@]}"
  fi
}

这个版本试图让你调用的命令看到一个终端,如果实际上有一个。也就是说,无论脚本是否是管道的一部分,它都应该按照预期的方式运行。
然而,该函数不能保证缩进,因为在每行前面加上空格并不能阻止回车符(\r)跳回到行首。还有很多方法可以将光标移动到缩进之前。
如果只是为了视觉效果,DEC私人模式设置(DECSET)与设置左,右边距(DECSLRM)功能将是完美的,实际上增加终端的左边距。不幸的是--至少在我测试的时候--切换到该模式和从该模式返回会清除屏幕,这样你就看不到缩进的输出了。

相关问题