将并发的bash代码移植到powershell

发布于 01-21 18:21 字数 2229 浏览 3 评论 0 原文

我有以下函数编写存储( sync in unix上):

# Sync Progress Function
function syncStorage {

  printq "Writing storage, may take more than 5 minutes."
  printq "Although it seems slow, consider this process like flashing an ISO to a USB Drive."
  printq "Below is an innacurate indicator of mB left to write. It may decrease hundreds of megabytes in seconds."

  # shellcheck disable=SC2016
  sync & {
    # If the unsynced data (in kB) is greater than 50MB, then show the sync progress
    while [[ $(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+') -gt 5000 ]]; do
      SYNC_MB=$(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf "%.2fMB\n",$1}')
      echo -en "\r${SYNC_MB}"
      sleep 1
    done
  }

  echo

  #watch -n 1 'grep -e Dirty: /proc/meminfo | grep --color=never -o '\''[0-9]\+'\'' | awk '\''{$1/=1024;printf "%.2fMB\n",$1}'\'''
  #grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf "%.2fMB\n",$1}'
}

我想将其移植到PowerShell,并到目前为止这样做:

sync & {
      # If the unsynced data (in kB) is greater than 50MB, then show the sync progress
      # You can replace contents in $(...) with 5001 for testing purposes
      while ( $(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+') -gt 5000 ) {
        SYNC_MB=$(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf "%.2fMB\n",$1}')
        echo -en "\r${SYNC_MB}"
        sleep 1
      }
    }

PowerShell接受此语法,但返回:

Id     Name            PSJobTypeName   State         HasMoreData     Location
--     ----            -------------   -----         -----------     --------  
45     Job45           BackgroundJob   Running       True            localhost 

      # If the unsynced data (in kB) is greater than 50MB, then show the sync progress
      while ( 43289423 -gt 5000 ) {
        SYNC_MB=$(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf "%.2fMB\n",$1}')
        echo -en "\r${SYNC_MB}"
        sleep 1
      }
    

它不运行该语法代码,它只是将其打印出来。当您用任何值(例如5001以满足WALE循环)替换$(...)时,相同的行为仍然存在。有什么想法吗?

I have the function below for writing storage (sync on Unix):

# Sync Progress Function
function syncStorage {

  printq "Writing storage, may take more than 5 minutes."
  printq "Although it seems slow, consider this process like flashing an ISO to a USB Drive."
  printq "Below is an innacurate indicator of mB left to write. It may decrease hundreds of megabytes in seconds."

  # shellcheck disable=SC2016
  sync & {
    # If the unsynced data (in kB) is greater than 50MB, then show the sync progress
    while [[ $(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+') -gt 5000 ]]; do
      SYNC_MB=$(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf "%.2fMB\n",$1}')
      echo -en "\r${SYNC_MB}"
      sleep 1
    done
  }

  echo

  #watch -n 1 'grep -e Dirty: /proc/meminfo | grep --color=never -o '\''[0-9]\+'\'' | awk '\''{$1/=1024;printf "%.2fMB\n",$1}'\'''
  #grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf "%.2fMB\n",$1}'
}

I want to port it to Powershell, and have done this so far:

sync & {
      # If the unsynced data (in kB) is greater than 50MB, then show the sync progress
      # You can replace contents in $(...) with 5001 for testing purposes
      while ( $(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+') -gt 5000 ) {
        SYNC_MB=$(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf "%.2fMB\n",$1}')
        echo -en "\r${SYNC_MB}"
        sleep 1
      }
    }

Powershell accepts this syntax, but returns:

Id     Name            PSJobTypeName   State         HasMoreData     Location
--     ----            -------------   -----         -----------     --------  
45     Job45           BackgroundJob   Running       True            localhost 

      # If the unsynced data (in kB) is greater than 50MB, then show the sync progress
      while ( 43289423 -gt 5000 ) {
        SYNC_MB=$(grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf "%.2fMB\n",$1}')
        echo -en "\r${SYNC_MB}"
        sleep 1
      }
    

It doesn't run the code, it just prints it out. The same behavior persists when you replace the $(...) with any value (e.g. 5001 to satisfy the while loop) in the while loop's condition. Any ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

终陌 2025-01-28 18:21:17

尽管在表面上相似,但 {...} 在bash vs. powershell中的根本不同

  • 在bash中,这是一种执行直接在呼叫者的范围中。

  • 在PowerShell中,这是一种将语句分组到a 脚本块 ,这是可重复使用的代码单位,要么在 child scope >,通过& 调用操作员,或直接通过呼叫者的范围,通过 dot-sourcoring oterator

    • 如果您像您一样输出脚本块 no 执行会发生,并且其 verbatim content (sans { } )打印到显示。

相比之下,在 shells中,a shell & 都可以异步启动背景作业,在PowerShell(仅核心)中是隐式等效的,即使用 start-job cmdlet。

因此,以下bash呼叫模式:

# Bash: These are really two separate statements:
#       `sync &` to launch `sync` in the background, 
#       and `{ ...; }` to execute commands synchronously in the foreground.
# For clarity, you could place the statements on separate lines.
sync & { ...; }

对应于powershell中的以下内容:

# PowerShell:
# Note: You may prefer `&` to `.` in order to create a child scope
#       whose variables are limited to that scope.
# Here too you could place the statements on separate lines.
sync & . { ... }

单独,将bash代码转换为powershell :

  • 与bash中不同,powershell中的变量分配存在:

    。 /p>

    • 也需要 $ Sigil也在那里;例如, $ sync_mb = ... 而不是 sync_mb = ...
    • 正如上面的并置所显示的那样,PowerShell还允许Whitespace包围 = sissigment operator
  • 与Bash不同,PowerShell的 -gt 不是独家 numeric :它是一个比单个运算符,也可与 string lhs values一起使用,在这种情况下,它执行词法比较。

    • 因此,为了与LHS进行数值比较,该LHS是外部程序的输出,例如 grep ,它总是a string ,您需要将其施放为适当的数字类型,通常 [int] ;提供简单的示例:

       (/bin/echo 10)-gt 2#! $ false-词汇比较
      
      [int](/bin/echo 10)-gt 2#ok:$ true-数值比较
       
  • 与bash不同, $(...) subexpression操作员


  • echo echo 不参考外部/bin/echo 实用程序,但是 写出 cmdlet,它既不理解> en options nock 选项,也不了解 \ -Escaped逃脱序列,鉴于PowerShell使用`,所谓的回避角色。

    • 虽然您可以通过其完整路径调用/bin/echo ,但PowerShell方法是使用 write-host cmdlet,如下所示。

    • Alternatively, as you've discovered, PowerShell has a dedicated cmdlet for progress displays,

  • 由于长期存在且高度不幸的错误,PowerShell-至少7.2.2-无法正确通过 chars。 >手动 \ -escaping ,甚至在 verbatim(single-Quoted)字符串('...'...'...' /code>命令。

​脚本块的儿童分割执行,并假设同步是PowerShell script sync.ps1 )或外部实用程序,将语句放在单独的行上:

sync &
& {
  while ([int] (grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+') -gt 5000 ) {
    $SYNC_MB = grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf \"%.2fMB\n\",$1}'
    Write-Host -NoNewLine "`r${SYNC_MB}"
    sleep 1
  }
}

注意:如果同步是PowerShell function ,以上是行不通的,因为后台作业不共享状态状态有了呼叫者,对其功能一无所知(除了通过auto-loading提供的功能模块)。

While superficially similar, { ... } in Bash vs. PowerShell are fundamentally different:

  • In Bash, it is a way to group statements to be executed instantly, directly in the caller's scope.

  • In PowerShell, it is a way to group statements into a script block, which is a reusable unit of code to be executed on demand, either in a child scope, via &, the call operator, or directly in the caller's scope, via ., the dot-sourcing operator.

    • If you output a script block by itself, as you did, no execution happens and its verbatim content (sans { and }) prints to the display .

By contrast, in both shells, a post-positional & serves to asynchronously launch a background job, which in PowerShell (Core only) is the implicit equivalent of using the Start-Job cmdlet.

Therefore, the following Bash call pattern:

# Bash: These are really two separate statements:
#       `sync &` to launch `sync` in the background, 
#       and `{ ...; }` to execute commands synchronously in the foreground.
# For clarity, you could place the statements on separate lines.
sync & { ...; }

corresponds to the following in PowerShell:

# PowerShell:
# Note: You may prefer `&` to `.` in order to create a child scope
#       whose variables are limited to that scope.
# Here too you could place the statements on separate lines.
sync & . { ... }

Separately, there are problems with your translation of your Bash code to PowerShell:

  • Unlike in Bash, variable assignments in PowerShell:

    • require the $ sigil there too; e.g., $SYNC_MB = ... instead of SYNC_MB=...
    • As the above juxtaposition shows, PowerShell also permits whitespace to surround =, the assignment operator.
  • Unlike in Bash, PowerShell's -gt isn't exclusively numeric: it serves as the single greater-than operator that also works with string LHS values, in which case it performs lexical comparison.

    • Therefore, in order to perform numerical comparison with an LHS that is the output from an external program such as grep, which is invariably a string, you need to cast it to an appropriate number type, typically [int]; to provide simple examples:

      (/bin/echo 10) -gt 2 # !! $false - LEXICAL comparison
      
      [int] (/bin/echo 10) -gt 2 # OK: $true - NUMERICAL comparison
      
  • Unlike in Bash, $(...), the subexpression operator is rarely needed outside expandable (double-quoted) string ("..."):

    • In variable assignments, you need no operator at all.
    • To make a command's output participate in a larger expression, it is usually better to use (...), the grouping operator
  • echo doesn't refer to the external /bin/echo utility, but is a built-in alias of the Write-Output cmdlet, which understands neither the -en options nor \-escaped escape sequences, given that PowerShell uses `, the so-called backtick, as its escape character.

    • While you could call /bin/echo via its full path, the PowerShell way is to use the Write-Host cmdlet, as shown below.

    • Alternatively, as you've discovered, PowerShell has a dedicated cmdlet for progress displays, Write-Progress, but note that its downside is that it can slow the overall operation down noticeably.

  • Due to a long-standing and highly unfortunate bug, PowerShell - up to at least 7.2.2 - doesn't properly pass " chars. embedded in external-program arguments, necessitating their manual \-escaping, even inside verbatim (single-quoted) string ('...'), such as in your awk command.

To put it all together, using & for child-scoped execution of the script block, and assuming that sync is either a PowerShell script (sync.ps1) or an external utility, placing the statements on separate lines:

sync &
& {
  while ([int] (grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+') -gt 5000 ) {
    $SYNC_MB = grep -e Dirty: /proc/meminfo | grep --color=never -o '[0-9]\+' | awk '{$1/=1024;printf \"%.2fMB\n\",$1}'
    Write-Host -NoNewLine "`r${SYNC_MB}"
    sleep 1
  }
}

Note: If sync were a PowerShell function, the above wouldn't work, because background jobs do not share state with the caller and know nothing about its functions (except functions provided via auto-loading modules).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文