Pull to refresh

Comments 26

разработчики под Windows хотят получить лёгкий доступ к этим командам в повседневной работе
разработчики обычно как раз не хотят. У них полным-полно других, не менее (а то и более) мощных и удобных инструментов. Вот админам, эникейшикам и любителям небольших скриптов для себя — да, другое дело. Заметьте, это вовсе не унижает перечисленные профессии и занятия, просто они другие.
Похоже, у вас очень узкое представление о разработчиках, либо у вас очень специфические задачи
Наверно, Вы правы. 40 лет личного программленья и руководства командой программёров явно недостаточно для формирования сколько-нибудь значимого мнения.
Собственно, давно использую «Bash for windows», который идет в составе Git'а.
Ставится в пару кликов без каких-либо костылей.
Для Сисадминов, что привыкли иметь дело с Linux — вещь незаменимая и куда более удобная, чем PowerShell (К которому ещё и привыкать надо).

У bash есть взаимодействие с AD, преобразование объектов в Sid и обратно и вот это всё?

Ну совсем без костылей не обойтись, да.
Вот только Bash вполне может воспринимать команды тогоже PowerShell'а. Только с башем работать както легче…
В Powershell очень не хватает нормальной работы с History и было бы удобно иметь что-то наподобие Ctrl+R под которой запускается «hh» от ultradvorka.

Начиная с какой-то версии они начали встраивать PSReadline, в котором Ctrl-R работает из коробки. Попробуйте :)

в 5.1 работает точно — спасибо :)
Но работает не так как hh от ultradvorka — выводит только одну строку в которой искомый паттерн попадается в последней команде в хистори — не то :(
При этом Get-History всё ещё выводит только историю текущей сессии… Как так-то? :(

Перешёл на WSL 2, иногда использую как раз команды powershell(например для получения информации по занятой памяти) и файлы .exe (например для копирования из vim в буфер винды) в нём, но не наоборот. У каждого конечно свои задачи, но добавить ещё сюда новый виндовый терминал и необходимость в таком решении полностью отпадёт.

Если абстрагироваться от вопроса, какая ОС лучше, то есть несколько моментов, которые у винды неудобнее в консоли. Первое — обратные слэши. В других операционках используется обычный слэш для пути, а обратный для экранирования. Обычный легче набирать, так как он на двух кливишах и без шифтов, обратный же на одной и с шифтом. Второе — верхний регистр. Имена программ редко содержат верхний регистр, а вот ключи довольно часто, особенно powershell. В терминале сильно работаешь клавой, и эти мелочи уменьшают продуктивность. Не зря например в питоне отказались от скобок и точек с запятой, так тупо меньше и легче набирать. Все эти штуки с wsl прикольно, но это больше похоже на крик бессилия, типа возьмите нашу консоль, мы прикрутим к ней что угодно, лишь бы вы её полюбили. Я годами ждал, терпел и ждал, когда всё пойдёт хорошо, но в итоге наигрался в игры, со спокойной душой поставил минт и начал получать удовольствие от того, что нет теперь 'C:\Program Files', а есть '/usr/bin', нет 'C:\Documents and Settings\Application Data\Roaming', а есть '/home//.config'. Может я привёл не полные аналоги папок, ну я думаю вы поняли.

обратный же на одной и с шифтом
С каких это пор он с шифтом? Более того, он набирается в любой раскладке одной и той же клавишей, в отличие от.
Имена программ редко содержат верхний регистр, а вот ключи довольно часто
Это вы точно про Windows? А то я тут ключи ls посмотрел, например.

Вы правы, без шифта. А что с ключами ls? Да есть в верхнем регистре, но они однобуквенные, в некоторых программах много ключей, и только нижнего регистра не хватает. Открыл википедию про powershell. Таблица сравнения командлетов с аналогичными командами. Зачем писать Get-Location, если можно написать get-location. Два раза нужно нажимать шифт. Это избыточно. Нам же не любоваться потом тем, что мы там написали.

С ключами ls то, что -a и -A, -b и -B (и далее по списку) — это разные ключи. И такое сплошь и рядом.
Зачем писать Get-Location, если можно написать get-location.
Так а кто мешает? В powershell команды нечувствительны к регистру.

А что, в Windows 10 отменили обычные слэши в путях?
"C:/Program Files" раньше тоже работало.
Да и буква диска обычно не нужна, так что путь /Users/Goodkat/Documents в Windows мало отличается от /home/Goodkat/Documents в GNU/Linux.

Вы о чём, вообще?


WSL появилось в Windows 10. В статье и вашем комментарии речь о WSL.


До Windows 10 (скорее всего и в Windows 10 тоже — было бы странным ломать обратную совместимость, но я не проверял) в путях можно использовать прямые слэши наравне с обратными.


А теперь поясните, пожалуйста, что вы имели в виду в своём последнем комментарии.

Все известные мне системные API давно умели в прямые слэши в путях (кроме разных интересных случаев с UNC и т.п.). Ну то есть как минимум с XP, а то и с NT4 это работает нормально.


Единственная существенная проблема, если вы пытаетесь перейти на использование прямых слэшей везде — это cmd.exe, он не любит такие слэши в некоторых случаях (в большинстве?). А всё остальное обычно работает.

Буква диска обычно не нужна, только если у вас всё на одном диске.


Само по себе утверждение, на мой взгляд, опасное — вон, ребята в Meteor в течение очень долгого времени не могли починить старт приложения с любого другого диска, кроме C — из-за того, что думали сходным образом :)


Работать с путями стоит очень осторожно. Хотя если вы не разрабатываете софт, а пользуетесь уже готовым, в рамках повседневной деятельности можно спокойно передавать пути без указания диска. Вы верно заметили, что это должно работать.

Да, спасибо, я это понял и просто на всякий случай предупредил о более общих проблемах, которые возникают на практике, и поделился смешными историями.


Ну, мало ли, вдруг кто-то из участников дискуссии считает, что уже давно на всех Windows-машинах диск остался только один? :)


Это ни в коем случае не возражение, а скорее дополнение к сказанному вами.

Странно пользователям Windows жаловаться на отсутствие утилит grep и sed.
Ведь их можно просто установить .

Ну Cygwin наше всё. Без него вообще никуда, я считаю.
Полезные графические утилиты там тоже присутствуют. Мне например нравится baobab
Статье не хватает тега «Троллейбус из буханки хлеба».
Это не про удобство работы.
Реквестирую вставку apt-get update && apt-get upgrade, чтобы оно научилось все-таки нормально обновляться…
У меня не работает! Вот мой конфиг:
конфиг
# The commands to import.
$commands = "sudo", "awk", "emacs", "grep", "head", "less", "ls", "man", "sed", "seq", "ssh", "tail", "vim", "vi", "nano", "apt", "wget", "curl"
 
# Register a function for each command.
$commands | ForEach-Object { Invoke-Expression @"
Remove-Alias $_ -Force -ErrorAction Ignore
function global:$_() {
    for (`$i = 0; `$i -lt `$args.Count; `$i++) {
        # If a path is absolute with a qualifier (e.g. C:), run it through wslpath to map it to the appropriate mount point.
        if (Split-Path `$args[`$i] -IsAbsolute -ErrorAction Ignore) {
            `$args[`$i] = Format-WslArgument (wsl.exe wslpath (`$args[`$i] -replace "\\", "/"))
        # If a path is relative, the current working directory will be translated to an appropriate mount point, so just format it.
        } elseif (Test-Path `$args[`$i] -ErrorAction Ignore) {
            `$args[`$i] = Format-WslArgument (`$args[`$i] -replace "\\", "/")
        }
    }
 
    if (`$input.MoveNext()) {
        `$input.Reset()
        `$input | wsl.exe $_ (`$args -split ' ')
    } else {
        wsl.exe $_ (`$args -split ' ')
    }
}
"@
}
function global:$_() {
    …
 
    `$defaultArgs = ((`$WslDefaultParameterValues.$_ -split ' '), "")[`$WslDefaultParameterValues.Disabled -eq `$true]
    if (`$input.MoveNext()) {
        `$input.Reset()
        `$input | wsl.exe $_ `$defaultArgs (`$args -split ' ')
    } else {
        wsl.exe $_ `$defaultArgs (`$args -split ' ')
    }
    $WslDefaultParameterValues["grep"] = "-E"
    $WslDefaultParameterValues["less"] = "-i"
    $WslDefaultParameterValues["ls"] = "-AFh --group-directories-first"
}
# Register an ArgumentCompleter that shims bash's programmable completion.
Register-ArgumentCompleter -CommandName $commands -ScriptBlock {
    param($wordToComplete, $commandAst, $cursorPosition)
 
    # Map the command to the appropriate bash completion function.
    $F = switch ($commandAst.CommandElements[0].Value) {
        {$_ -in "awk", "grep", "head", "less", "ls", "sed", "seq", "tail"} {
            "_longopt"
            break
        }
 
        "man" {
            "_man"
            break
        }
 
        "ssh" {
            "_ssh"
            break
        }
 
        Default {
            "_minimal"
            break
        }
    }
 
    # Populate bash programmable completion variables.
    $COMP_LINE = "`"$commandAst`""
    $COMP_WORDS = "('$($commandAst.CommandElements.Extent.Text -join "' '")')" -replace "''", "'"
    for ($i = 1; $i -lt $commandAst.CommandElements.Count; $i++) {
        $extent = $commandAst.CommandElements[$i].Extent
        if ($cursorPosition -lt $extent.EndColumnNumber) {
            # The cursor is in the middle of a word to complete.
            $previousWord = $commandAst.CommandElements[$i - 1].Extent.Text
            $COMP_CWORD = $i
            break
        } elseif ($cursorPosition -eq $extent.EndColumnNumber) {
            # The cursor is immediately after the current word.
            $previousWord = $extent.Text
            $COMP_CWORD = $i + 1
            break
        } elseif ($cursorPosition -lt $extent.StartColumnNumber) {
            # The cursor is within whitespace between the previous and current words.
            $previousWord = $commandAst.CommandElements[$i - 1].Extent.Text
            $COMP_CWORD = $i
            break
        } elseif ($i -eq $commandAst.CommandElements.Count - 1 -and $cursorPosition -gt $extent.EndColumnNumber) {
            # The cursor is within whitespace at the end of the line.
            $previousWord = $extent.Text
            $COMP_CWORD = $i + 1
            break
        }
    }
 
    # Repopulate bash programmable completion variables for scenarios like '/mnt/c/Program Files'/<TAB> where <TAB> should continue completing the quoted path.
    $currentExtent = $commandAst.CommandElements[$COMP_CWORD].Extent
    $previousExtent = $commandAst.CommandElements[$COMP_CWORD - 1].Extent
    if ($currentExtent.Text -like "/*" -and $currentExtent.StartColumnNumber -eq $previousExtent.EndColumnNumber) {
        $COMP_LINE = $COMP_LINE -replace "$($previousExtent.Text)$($currentExtent.Text)", $wordToComplete
        $COMP_WORDS = $COMP_WORDS -replace "$($previousExtent.Text) '$($currentExtent.Text)'", $wordToComplete
        $previousWord = $commandAst.CommandElements[$COMP_CWORD - 2].Extent.Text
        $COMP_CWORD -= 1
    }
 
    # Build the command to pass to WSL.
    $command = $commandAst.CommandElements[0].Value
    $bashCompletion = ". /usr/share/bash-completion/bash_completion 2> /dev/null"
    $commandCompletion = ". /usr/share/bash-completion/completions/$command 2> /dev/null"
    $COMPINPUT = "COMP_LINE=$COMP_LINE; COMP_WORDS=$COMP_WORDS; COMP_CWORD=$COMP_CWORD; COMP_POINT=$cursorPosition"
    $COMPGEN = "bind `"set completion-ignore-case on`" 2> /dev/null; $F `"$command`" `"$wordToComplete`" `"$previousWord`" 2> /dev/null"
    $COMPREPLY = "IFS=`$'\n'; echo `"`${COMPREPLY[*]}`""
    $commandLine = "$bashCompletion; $commandCompletion; $COMPINPUT; $COMPGEN; $COMPREPLY" -split ' '
 
    # Invoke bash completion and return CompletionResults.
    $previousCompletionText = ""
    (wsl.exe $commandLine) -split '\n' |
    Sort-Object -Unique -CaseSensitive |
    ForEach-Object {
        if ($wordToComplete -match "(.*=).*") {
            $completionText = Format-WslArgument ($Matches[1] + $_) $true
            $listItemText = $_
        } else {
            $completionText = Format-WslArgument $_ $true
            $listItemText = $completionText
        }
 
        if ($completionText -eq $previousCompletionText) {
            # Differentiate completions that differ only by case otherwise PowerShell will view them as duplicate.
            $listItemText += ' '
        }
 
        $previousCompletionText = $completionText
        [System.Management.Automation.CompletionResult]::new($completionText, $listItemText, 'ParameterName', $completionText)
    }
}
 
# Helper function to escape characters in arguments passed to WSL that would otherwise be misinterpreted.
function global:Format-WslArgument([string]$arg, [bool]$interactive) {
    if ($interactive -and $arg.Contains(" ")) {
        return "'$arg'"
    } else {
        return ($arg -replace " ", "\ ") -replace "([()|])", ('\$1', '`$1')[$interactive]
    }
}

Sign up to leave a comment.

Articles