Comments 26
разработчики под Windows хотят получить лёгкий доступ к этим командам в повседневной работеразработчики обычно как раз не хотят. У них полным-полно других, не менее (а то и более) мощных и удобных инструментов. Вот админам, эникейшикам и любителям небольших скриптов для себя — да, другое дело. Заметьте, это вовсе не унижает перечисленные профессии и занятия, просто они другие.
Ставится в пару кликов без каких-либо костылей.
Для Сисадминов, что привыкли иметь дело с Linux — вещь незаменимая и куда более удобная, чем PowerShell (К которому ещё и привыкать надо).
Начиная с какой-то версии они начали встраивать PSReadline, в котором Ctrl-R работает из коробки. Попробуйте :)
Перешёл на 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. Два раза нужно нажимать шифт. Это избыточно. Нам же не любоваться потом тем, что мы там написали.
А что, в Windows 10 отменили обычные слэши в путях?
"C:/Program Files" раньше тоже работало.
Да и буква диска обычно не нужна, так что путь /Users/Goodkat/Documents в Windows мало отличается от /home/Goodkat/Documents в GNU/Linux.
А что, у всех windows 10?
Вы о чём, вообще?
WSL появилось в Windows 10. В статье и вашем комментарии речь о WSL.
До Windows 10 (скорее всего и в Windows 10 тоже — было бы странным ломать обратную совместимость, но я не проверял) в путях можно использовать прямые слэши наравне с обратными.
А теперь поясните, пожалуйста, что вы имели в виду в своём последнем комментарии.
Все известные мне системные API давно умели в прямые слэши в путях (кроме разных интересных случаев с UNC и т.п.). Ну то есть как минимум с XP, а то и с NT4 это работает нормально.
Единственная существенная проблема, если вы пытаетесь перейти на использование прямых слэшей везде — это cmd.exe
, он не любит такие слэши в некоторых случаях (в большинстве?). А всё остальное обычно работает.
Буква диска обычно не нужна, только если у вас всё на одном диске.
Само по себе утверждение, на мой взгляд, опасное — вон, ребята в Meteor в течение очень долгого времени не могли починить старт приложения с любого другого диска, кроме C — из-за того, что думали сходным образом :)
Работать с путями стоит очень осторожно. Хотя если вы не разрабатываете софт, а пользуетесь уже готовым, в рамках повседневной деятельности можно спокойно передавать пути без указания диска. Вы верно заметили, что это должно работать.
Да, спасибо, я это понял и просто на всякий случай предупредил о более общих проблемах, которые возникают на практике, и поделился смешными историями.
Ну, мало ли, вдруг кто-то из участников дискуссии считает, что уже давно на всех Windows-машинах диск остался только один? :)
Это ни в коем случае не возражение, а скорее дополнение к сказанному вами.
Ведь их можно просто установить .
Ну 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]
}
}
Интегрируем команды Linux в Windows с помощью PowerShell и WSL