Все еще сталкиваются с проблемами при попытке превратить некоторые скрипты bash в черепаху, ноль терминированные строки, в частности находящиеся в виновнике

При попытке превратить некоторые (для меня:) идиомы bash в сценарии черепах, я все еще сталкиваюсь с проблемами. Это длинный пост, извините - вы можете просто пропустить вводные пояснения и перейти к актуальным вопросам ближе к концу - но я надеюсь ясно изложить свою точку зрения (вопросы) таким образом.

Одна идиома, которую я часто использую в сценариях bash, - это связывание воедино (piping) find, egrep и xargs со строкой, заканчивающейся нулем. Причина проста: даже имена файлов с пробелами и другими странными символами таким образом не вызывают проблем.

Я бы использовал что-то вроде этого:

находить. имя "*" -print0 ... | egrep -z -Z ... | xargs -0 ...

Иногда я хотел бы работать построчно над файлами, соответствующими -L 1

находить. имя "*" -print0 ... | egrep -z -Z ... | xargs -0 -L 1 ...

Или вместо xargs -0... я бы использовал другой инструмент, например rsync с ssh, который также понимает строки с нулевым символом в конце: -0

Синхронизировать / сохранить (необходимое) содержимое моего текущего каталога в другом каталоге, например. Я бы использовал что-то вроде:

binaries="exe$"
logfiles="log$"
pidfiles="pid$"
shakestuff="\_shake|\_build|\.\.database"
pat="^\.$|/dist|\.cabal-sandbox|cabal\.sandbox\.config|$shakestuff|\.o$|\.dyn_o$|\.hi$|\.dyn_hi$|\.hdevtools.sock$|$binaries|$logfiles|$pidfiles|TAGS"

find . -iname "*" -print0 -type f | egrep -z -Z -v "$pat" | rsync -a -e ssh --delete --progress --files-from=- -0 ./ .../path/to/some/other/dir
  • команда find печатает все файлы в текущем каталоге, завершается нулем: -print0

  • egrep -v "$ pat", сохраняет из этого списка файлов только те, которые не соответствуют шаблону $pat, только необходимые файлы, т. е. я не беспокоюсь о синхронизации / сохранении файлов в каталоге.cabal-sandbox, например, и egrep нахождение в середине этой цепочки должно потреблять, а также создавать строки с нулевыми концами здесь: -z -Z Паттерн патт собирается заранее по частям.

  • rsync с ssh получает указание на получение ввода от stdin: --files-from=-, снова завершается null: -0 (обратите внимание, что в целом "rsync... from to" ведет себя очень по-разному, в зависимости от того, где находится каталог из задается с косой чертой, как здесь: ./ или нет, здесь это менее важно, так как входные данные для rsync поступают из stdin: -)

Теперь я попытался превратить это в сценарий черепахи, но с некоторым успехом, т. Е., Но столкнулся с некоторыми проблемами и хотел бы превратить это в более идиоматическую черепаху:

Для полноты картины, вот мой в настоящее время работающий скрипт в файле sync.hs, который вызывается с помощью небольшого скрипта bash, я могу вызвать sync.hs.

  1. либо просто показать список рассматриваемых файлов: sync.hs -e

  2. или синхронизировать их с другим каталогом, например, так: sync.hs --to /path/to/other/dir

Вот этот код (runturtle):

#!/bin/sh
exec cabal exec runhaskell -- "$@"

Вот код (sync.hs):

#!/usr/bin/env runturtle

{-# LANGUAGE OverloadedStrings #-}

-- {-# LANGUAGE ExtendedDefaultRules #-}

{-# OPTIONS_GHC -fno-warn-type-defaults #-}


import Turtle


data Opts = Opts {
  doEcho :: Bool
  , toDir :: Turtle.FilePath
  }
  deriving (Show)

parser :: Parser Opts
parser = Opts <$>
     (switch "echo" 'e' "echo the files considered for synchronizing")
     <*> (optPath "to" 't' "sync to dir")

binaries="|\\./website$|srv$"

logfiles="|log$"

pidfiles="|pid$|pnm$"

shakestuff="|_shake|_build|\\.\\.database"

pat="^\\.$"
  <>"|/dist|\\.cabal-sandbox|cabal\\.sandbox\\.config"
  <> shakestuff
  <>"|\\.git|\\.o$|\\.dyn_o$|\\.hi$|\\.dyn_hi$|\\.hdevtools.sock$"
  <> binaries
  <> logfiles
  <> pidfiles
  <>"|TAGS"

sync :: Opts -> IO ()
sync opts = do {

  ; echo "syncing..."
  ; when (doEcho opts)
(do {
    ; echo $ "pat: " <> pat

    ; sh $ do inproc  "find" [".", "-iname", "*", "-print0", "-type", "f"] empty 
        & inproc "egrep" ["-z", "-Z" , "-v", pat]
        & inproc "xargs" ["-0", "-L", "1"]
        & grep (has ".")
        >>= echo
    ; exit ExitSuccess
    })




  ; do {
  ; let txt = "find . -iname \"*\" -print0 -type f | egrep -z -Z -v \"" <> pat <>"\" | rsync -a -e ssh --delete  --progress --files-from=- -0 ./ "
          <> format fp (toDir opts)
  ; echo txt
  ; shell txt empty
  ; return ()
  }


  ; return ()

  }                                      



main :: IO ()
main = (do {
       ; opts <- options "sync file to another directory" parser
       ; print (opts)
       ; sync opts
       ; return ()

       })

Теперь вот мои проблемы с этим сценарием:

Прежде всего: я могу запустить это из командной строки, моя проверка синтаксиса flycheck в emacs, использующая либо ghc, либо hdevtools, работает нормально, поэтому теперь я получаю преимущества строгой типизации Haskell для скриптов оболочки (спасибо, что, кстати, за создание turtle). Я даже могу использовать черепаху в командной строке (Cabal Repl)

cabal repl
> :set -XOverloadedStrings
> import Turtle
> ls "."
> view (shell "whatever cmd" empty)

и т.д., но если я загружаю свой скрипт sync.hs, я не могу получить доступ к его частям (функции определены в sync)

> :l sync.hs 
[1 of 1] Compiling Main             ( sync.hs, interpreted )
Ok, modules loaded: Main.

Я хотел бы видеть шаблон, определенный выше, например:

> pat

<interactive>:12:1:
Not in scope: ‘pat’
Perhaps you meant ‘cat’ (imported from Turtle)

Я хотел бы использовать функции, определенные в sync.hs, как ярлыки для экспериментов, например. как это

> view $ inproc "find" [".", "-iname", "*", "-print0", "-type", "f"] empty & inproc "egrep" ["-z", "-Z" , "-v", pat]

<interactive>:15:111:
Not in scope: ‘pat’
Perhaps you meant ‘cat’ (imported from Turtle)

Во-вторых, вы, возможно, заметили в моем скрипте выше, что я использовал "более идиоматическую" черепаху в случае эха:

; sh $ do inproc  "find" [".", "-iname", "*", "-print0", "-type", "f"] empty 
    & inproc "egrep" ["-z", "-Z" , "-v", pat]
    & inproc "xargs" ["-0", "-L", "1"]
    & grep (has ".")
    >>= echo

то есть. Я использую стиль трубопровода в черепахе: функция приложения, здесь в обратном порядке с &, более идиоматично, по крайней мере, чем в случае toDir, где я фактически полагаюсь на bash для выполнения этой работы:

; let txt = "find . -iname \"*\" -print0 -type f | egrep -z -Z -v \"" <> pat <>"\" | rsync -a -e ssh --delete  --progress --files-from=- -0 ./ "
    <> format fp (toDir opts)
; echo txt
; shell txt empty

Но даже в этом более идиоматическом случае эха мне пришлось прибегнуть к некоторому обходному пути: grep (has "."). Если я не использую это, я получаю увидеть пустые строки:

turtle> view $ inproc "find" [".", "-iname", "*", "-print0", "-type", "f"] empty & inproc "egrep" ["-z", "-Z" , "-v", "\\.cabal-sandbox|/dist"]

output (здесь много опущено, но в самом конце смотрите одиночный "\NUL"):

"...ntax.hs\NUL./static/lib-pi-forall/src/PiForall/Parser.hs\NUL./static/lib-pi-forall/src/PiForall/TypeCheck.hs\NUL./static/lib-pi-forall/LICENSE\NUL./shclean.do\NUL./TAGS\NUL./T10.hs\NUL./todo-yet-stop-the-program-as-in-running-if-not-told-another\NUL./talks\NUL./index.html\NUL./T1.hs.orig\NUL./sbbuild.sh\NUL./_shake\NUL./_shake/Main.hi\NUL./_shake/Main.dyn_o\NUL./_shake/build\NUL./_shake/Main.o\NUL./_shake/Main.dyn_hi\NUL./T4.hs\NUL./sync.hs\NUL./etc\NUL./.hdevtools.sock\NUL./more-stuff.hs\NUL./my.hs\NUL./T9.hs\NUL./snap-index\NUL./T6.hs\NUL./etc.html\NUL./cabalfile.hs\NUL./todo-maybe-issue-start-stop-restart-july2016\NUL./try-turtle-urwclassico.do\NUL./install.do\NUL./update-rc\NUL./index\NUL./done-pipe\NUL./clean.do\NUL./bootstrap.do\NUL./mystuff.cabal\NUL./pire\NUL./log\NUL./build.sh\NUL./goodsync.hs\NUL./cmds.hs\NUL./LICENSE\NUL./dry.do\NUL./T5.hs\NUL./snap-pire\NUL"
"\NUL"

Посмотрите на пустые строки, которые я получаю в конце, если я не буду пытаться удалить их с помощью grep (has ".")

turtle> view $ inproc "find" [".", "-iname", "*", "-print0", "-type", "f"] empty & inproc "egrep" ["-z", "-Z" , "-v", "\\.cabal-sandbox|/dist"] & inproc "xargs" ["-0", "-L", "1"]

(again lots of output omitted)
"./done-pipe"
"./clean.do"
"./bootstrap.do"
"./mystuff.cabal"
"./pire"
"./log"
"./build.sh"
"./goodsync.hs"
"./cmds.hs"
"./LICENSE"
"./dry.do"
"./T5.hs"
"./snap-pire"
""
""
""
""
turtle> 

Почему это? В Bash я не обязан это делать! Есть какой-нибудь лучший / рекомендуемый способ использования строк с нулевым символом в черепахе?

И, наконец, что немаловажно, я не смог придумать идиоматическое решение для "черепашек" для другого фрагмента кода rsync. Вот попытка, но посмотрим, что произойдет: некоторые файлы передаются, но rsync жалуется, что мой текущий каталог dir /home/rx/work/servant/ не найден с нулевым окончанием: link_stat "/home/rx/work/servant/#012"не удалось: (ну да: его имя просто"/home/rx/work/servant/" not "/home/rx/work/servant/#012")

; view $ inproc "find" [".", "-iname", "*", "-print0", "-type", "f"] empty 
    & inproc "egrep" ["-z", "-Z", "-v", pat]
    & grep (has ".")
    & shell ("rsync -a -e ssh --delete --progress --files-from=- -0 ./ " <> (format fp $ toDir opts))


rx@softland ~/work/servant $ ./sync.hs --to ~/tmp/website_
Opts {doEcho = False, toDir = FilePath "/home/rx/tmp/website_"}
syncing...
building file list ... 
rsync: link_stat "/home/rx/work/servant/\#012" failed: No such file or directory (2)
135 files to consider
./
q
      8,715 100%    0.00kB/s    0:00:00 (xfr#1, to-chk=95/135)
sync.hs
      2,034 100%    1.94MB/s    0:00:00 (xfr#2, to-chk=86/135)
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1183) [sender=3.1.1]
ExitFailure 23
rx@softland ~/work/servant $

Но на самом деле я хотел бы использовать даже inproc для части rsync (с или без grep (имеет "."))

; view $ inproc "find" [".", "-iname", "*", "-print0", "-type", "f"] empty 
  & inproc "egrep" ["-z", "-Z", "-v", pat]
  & grep (has ".")
  & inproc "rsync" ["-a", "-e", "ssh", "--delete", "--progress", "--files-from=-", "-0", "./", format fp $ toDir opts]



rx@softland ~/work/servant $ ./sync.hs --to ~/tmp/website_
Opts {doEcho = False, toDir = FilePath "/home/rx/tmp/website_"}
syncing...
"building file list ... "
rsync: link_stat "/home/rx/work/servant/\#012" failed: No such file or directory (2)
" 0 files...\r 100 files...\r137 files to consider"
"./"
"sync.hs"
"\r          2,053 100%    0.00kB/s    0:00:00  \r          2,053 100%    0.00kB/s    0:00:00 (xfr#1, to-chk=86/137)"
rsync error: some files/attrs were not transferred (see previous errors) (code 23) at main.c(1183) [sender=3.1.1]
rx@softland ~/work/servant $

Заранее спасибо.

0 ответов

Другие вопросы по тегам