Home > Mobile >  Powershell Core, MXLinuxv21, running linux /usr/bin/x command results in "no file found" f
Powershell Core, MXLinuxv21, running linux /usr/bin/x command results in "no file found" f

Time:01-14

I have a powershell script with three sections: 1. modify file names to remove MicrosoftOS reserved characters; 2. run /usr/bin/flac to convert *.wav files to *.flac, 3. use .dll to copy ID3 tags from *.mp3 files to *.flac files.

All three sections of this script worked on my previous Kubuntu v22.10 system. This script fails at step 2 on MXLinux v21. The error is "File not found" for the objects of the /usr/bin/flac command. /usr/bin/flac loads, but says that it cannot find the file given to it. Steps 1 and 3 work (I know this because the script takes an argument to skip step 2; thus I can run it if the *.wav files are already *.flac files, e.g., on a previous run where step 2 was successful but step 3 failed for some reason).

Here is the PS code fragment:

  [string] $flacEXE = '/usr/bin/flac'
  if($convert -eq "yes" || $convert -eq "Yes" || $convert -eq "YES") 
  {
    if (Test-Path -Path "$workingPath/*cr.wav")
    { 
      $CRFiles = Get-ChildItem -Path "$workingPath/*cr.wav"
      foreach ($crFile in $CRFiles)
      {
        $output = & $flacEXE "`"$crFile`""
        if ($LASTEXITCODE -ne 0) 
        {
          Write-Host "The flac conversion created an error..." -ForegroundColor Red
          Write-Host "$output" -ForegroundColor Red
        }
      }
    }
    else 
    {
      Write-Host "No ClickRepair files found but Convert was Yes ... Aborting script.`n" -ForegroundColor Red
      throw $_.Exception.Message
      exit      
    }
  }

If I run /usr/bin/flac from the prompt in powershell (e.g., in Visual Studio Code), it fails. If I run /usr/bin/flac from a linux terminal on the same files in the same folder, it works.

I think this must be some sort of permissions issue (scope issue?), but cannot figure it out. The files are on a NTFS USB volume mounted on /mnt/. I recently migrated to MXLinux and thus have recreated my system. This is my first use of this powershell script.

I should note that the concert of Set-ExecutionPolicy is not valid for Powershell Core on Linux, only on Windows systems, so that's not useful.

CodePudding user response:

Replace:

$output = & $flacEXE "`"$crFile`""

with:

$output = & $flacEXE $crFile
  • Unlike in POSIX-compatible shells such as bash, you do not need to enclose variable references passed as arguments in "..." in PowerShell - PowerShell has no equivalent to the so-called shell expansions of POSIX-compatible shells, notably not word-splitting; therefore, a value with spaces doesn't need protecting with "..." in PowerShell.

  • That "`"$crFile`"" worked at all is only due to a longstanding bug in how PowerShell passes arguments with embedded double quotes to external programs up to PowerShell 7.2.x.

    • In PowerShell 7.3.0, this bug was fixed, so that the above now (correctly) passes the inner " as a a verbatim part of the argument to the target program. (However, "$crFile", would work in both 7.2.x and later, though the " are still unnecessary, as explained above).

    • See this answer for more information, including how to opt into the old, broken behavior for the sake of backward compatibility. Also note that the current plan is to continue to default to the new, correct behavior on Unix-like platforms only, and that on Windows some version after 7.3.1 may revert to the old, broken behavior by default, with the new, correct behavior requiring opt-in.


As an aside, re if($convert -eq "yes" || $convert -eq "Yes" || $convert -eq "YES"):

  • Replace if($convert -eq "yes" || $convert -eq "Yes" || $convert -eq "YES") with if ($convert -eq 'yes') - PowerShell is case-insensitive by default.[1] If you had to use multiple operations, you need to chain them with -or, not with || - || operates on the success status of commands, not on values; e.g.:

    • $true || 'never get here' and $false || 'never get here' do not trigger the RHS of ||, because both $true and $false are expression that execute successfully, irrespective of their value, and therefore do not trigger the RHS of the || pipeline-chain operator (applies analogously to &&).

    • For operations based on values (expression return values or command output), us the -or, the logical -or and -and operators.


[1] For case-sensitive behavior, use the c-prefixed variants of operands such as -eq; e.g., 'FOO' -ceq 'foo' is $false. Similarly, most standard cmdlets and the switch statement are case-insensitive by default, and offer a -CaseSensitive switch as opt-in.

  • Related