Komentowanie w skrypcie Bash wewnątrz polecenia wielowierszowego


164

Jak mogę skomentować każdy wiersz z poniższych wierszy skryptu?

cat ${MYSQLDUMP} | \
sed '1d' | \
tr ",;" "\n" | \
sed -e 's/[asbi]:[0-9]*[:]*//g' -e '/^[{}]/d' -e 's/""//g' -e '/^"{/d' | \
sed -n -e '/^"/p' -e '/^print_value$/,/^option_id$/p' | \
sed -e '/^option_id/d' -e '/^print_value/d' -e 's/^"\(.*\)"$/\1/' | \
tr "\n" "," | \
sed -e 's/,\([0-9]*-[0-9]*-[0-9]*\)/\n\1/g' -e 's/,$//' | \
sed -e 's/^/"/g' -e 's/$/"/g' -e 's/,/","/g' >> ${CSV}

Jeśli spróbuję dodać komentarz typu:

cat ${MYSQLDUMP} | \ # Output MYSQLDUMP File

Dostaję:

#: not found

Czy można tu komentować?


1
Cóż, jak zauważyłeś, jeśli najpierw wykonasz #, to \ stanie się tylko częścią komentarza, ale jeśli najpierw zrobisz \, to późniejsze znaki w wierszu zmieniają jego znaczenie z „kontynuacji wiersza” na „cytat”. Pomyślałem o jednym rozwiązaniu, podanym poniżej.
DigitalRoss

Odpowiedzi:


203

Będzie to wiązało się z pewnym narzutem, ale technicznie odpowiada na twoje pytanie:

echo abc `#Put your comment here` \
     def `#Another chance for a comment` \
     xyz, etc.

W szczególności w przypadku rurociągów istnieje czyste rozwiązanie bez kosztów ogólnych:

echo abc |        # Normal comment OK here
     tr a-z A-Z | # Another normal comment OK here
     sort |       # The pipelines are automatically continued
     uniq         # Final comment

Zobacz pytanie dotyczące przepełnienia stosu Jak umieścić komentarz wierszowy dla polecenia wielowierszowego .


1
Wydaje się dość skomplikowane, jeśli nie ma prostszej metody?
BassKozz

1
Ok, dodałem nieco prostszą odmianę.
DigitalRoss

1
Czy możesz zmodyfikować swoją odpowiedź tylko po to, aby pokazać, że ukośnik odwrotny nie jest potrzebny, więc mogę umieścić komentarze obok każdego wiersza i po prostu użyć potoku?
BassKozz

Sprawdziłem, że wersja pierwsza i druga działają. Czy możesz jednak wyjaśnić, dlaczego to robią i co się tutaj dzieje? Dzięki.
Faheem Mitha

1
Dziękuję za wyjaśnienie. Otworzyłem pytanie na unix.sx z prośbą o więcej szczegółów, polecenie bash wieloliniowe z komentarzami po znaku kontynuacji .
Faheem Mitha

39

Końcowy ukośnik odwrotny musi być ostatnim znakiem w wierszu, aby został zinterpretowany jako polecenie kontynuacji. Po nim nie są dozwolone żadne komentarze ani nawet spacje.

Pomiędzy poleceniami powinno być możliwe umieszczenie wierszy komentarza

# output MYSQLDUMP file
cat ${MYSQLDUMP} | \
# simplify the line
sed '/created_at/d' | \
# create some newlines
tr ",;" "\n" | \
# use some sed magic
sed -e 's/[asbi]:[0-9]*[:]*//g' -e '/^[{}]/d' -e 's/""//g' -e '/^"{/d' | \
# more magic
sed -n -e '/^"/p' -e '/^print_value$/,/^option_id$/p' | \
# even more magic
sed -e '/^option_id/d' -e '/^print_value/d' -e 's/^"\(.*\)"$/\1/' | \
tr "\n" "," | \
# I hate phone numbers in my output
sed -e 's/,\([0-9]*-[0-9]*-[0-9]*\)/\n\1/g' -e 's/,$//' | \ 
# one more sed call and then send it to the CSV file
sed -e 's/^/"/g' -e 's/$/"/g' -e 's/,/","/g' >> ${CSV}

12
Znak \ nie jest konieczny, gdy komponent polecenia potoku kończy się znakiem |
DigitalRoss

2
DigitalRoss, masz rację, mogę po prostu użyć potoku, a nie odwrotnego ukośnika, a wtedy moje #komentarze będą działać idealnie ... czy możesz to opublikować jako odpowiedź, abym mógł to zaakceptować.
BassKozz

8
„Powinieneś móc wstawiać wiersze komentarza między komendami”: nie, to działa tylko dlatego, że ostatnim zinterpretowanym znakiem w poprzednich wierszach jest |. Jeśli spróbujesz cat file1\<newline>#comment<newline>file2, zobaczysz, że nie dostaniesz cat file1 file2, ale raczej cat file1; file2.
wątpliwyjim

5
Jednak, jak wspominali inni, cat file1 | # comment<newline>sortdziała dobrze. Tak też cat file1 && # comment<newline>echo foo. Zatem komentarze mogą być dołączane po |lub &&lub ||, ale nie po `\` lub w środku polecenia.
wątpliwyjim

7

Jak zauważył DigitalRoss, końcowy ukośnik odwrotny nie jest konieczny, gdy wiersz kończy się |. Możesz umieścić komentarze w wierszu następującym po |:

 cat ${MYSQLDUMP} |         # Output MYSQLDUMP file
 sed '1d' |                 # skip the top line
 tr ",;" "\n" | 
 sed -e 's/[asbi]:[0-9]*[:]*//g' -e '/^[{}]/d' -e 's/""//g' -e '/^"{/d' |
 sed -n -e '/^"/p' -e '/^print_value$/,/^option_id$/p' |
 sed -e '/^option_id/d' -e '/^print_value/d' -e 's/^"\(.*\)"$/\1/' |
 tr "\n" "," |
 sed -e 's/,\([0-9]*-[0-9]*-[0-9]*\)/\n\1/g' -e 's/,$//' |   # hate phone numbers
 sed -e 's/^/"/g' -e 's/$/"/g' -e 's/,/","/g' >> ${CSV}

5

Odwrotny ukośnik ucieka z #, interpretując go jako znak dosłowny zamiast znaku komentarza.


3

$IFS komentarze hacki

Wykorzystuje Hack ekspansja parametr na $IFS, który jest używany do oddzielania słów poleceń:

$ echo foo${IFS}bar
foo bar

Podobnie:

$ echo foo${IFS#comment}bar
foo bar

Używając tego, możesz umieścić komentarz w wierszu poleceń z kontynuacją:

$ echo foo${IFS# Comment here} \
> bar
foo bar

ale komentarz będzie musiał być przed \kontynuacją.

Zwróć uwagę, że interpretacja parametrów jest wykonywana wewnątrz komentarza:

$ ls file
ls: cannot access 'file': No such file or directory
$ echo foo${IFS# This command will create file: $(touch file)}bar
foo bar
$ ls file
file

Rzadki wyjątek

Jedynym rzadkim przypadkiem niepowodzenia jest sytuacja, w której $IFSpoprzednio rozpoczęto od dokładnego tekstu, który jest usuwany przez rozszerzenie (tj. Po #znaku):

$ IFS=x
$ echo foo${IFS#y}bar
foo bar
$ echo foo${IFS#x}bar
foobar

Zwróć uwagę, że na finale foobarnie ma miejsca, co ilustruje problem.

Ponieważ $IFSdomyślnie zawiera tylko białe znaki, jest bardzo mało prawdopodobne, że napotkasz ten problem.


Kredyt do komentarza @ PJH za który wywołał tę odpowiedź.


1

Oprócz przykładów opracowanych przez DigitalRoss, oto inny formularz, którego możesz użyć, jeśli wolisz $()zamiast grawisów`

echo abc $(: comment) \
     def $(: comment) \
     xyz

Oczywiście możesz również użyć składni dwukropka z odwrotnymi apostrofami:

echo abc `: comment` \
     def `: comment` \
     xyz

Dodatkowe uwagi

Przyczyna $(#comment)nie działa, ponieważ gdy widzi #, traktuje resztę linii jako komentarze, w tym nawiasy zamykające:comment) . Dlatego nawiasy nigdy nie są zamknięte.

Backticks analizuje inaczej i wykryje zamykający backtick nawet po pliku #.


1
Czy stworzy to nową powłokę dla każdego komentarza?
lonix

0

Oto skrypt bash, który łączy idee i idiomy kilku poprzednich komentarzy, aby dostarczyć, wraz z przykładami, komentarze w wierszu o ogólnej formie ${__+ <comment text>}.

W szczególności

  • <comment text> może być wieloliniowy
  • <comment text> nie jest rozszerzany parametrami
  • nie pojawiają się żadne podprocesy (więc komentarze są wydajne)

Jest jeden na ograniczenie <comment text>, a mianowicie, niesymetryczne szelki '}'i nawiasy ')'muszą być chronione (tzn '\}'i'\)' ).

Jest jeden wymóg dotyczący lokalnego środowiska bash:

  • nazwa parametru __musi być cofnięta

Każda inna poprawna składniowo nazwa parametru bash będzie służyć zamiast __ , pod warunkiem, że nazwa nie ma ustawionej wartości.

Oto przykładowy skrypt

# provide bash inline comments having the form
#     <code> ${__+ <comment>} <code> 
#     <code> ${__+ <multiline
#                   comment>} <code>

# utility routines that obviate "useless use of cat"
function bashcat { printf '%s\n' "$(</dev/stdin)"; }
function scat { 1>&2 bashcat; exit 1; }

# ensure that '__' is unset && remains unset
[[ -z ${__+x} ]] &&  # if '__' is unset
  declare -r __ ||   # then ensure that '__' remains unset 
  scat <<EOF         # else exit with an error
Error: the parameter __='${__}' is set, hence the
  comment-idiom '\${__+ <comment text>}' will fail
EOF

${__+ (example of inline comments)
------------------------------------------------
the following inline comment-idiom is supported
    <code> ${__+ <comment>} <code> 
    <code> ${__+ <multiline
                  comment>} <code> 
(advisory) the parameter '__' must NOT be set;
  even the null declaration __='' will fail
(advisory) protect unbalanced delimiters \} and \) 
(advisory) NO parameter-expansion of <comment> 
(advisory) NO subprocesses are spawned
(advisory) a functionally equivalent idiom is 
    <code> `# <comment>` <code> 
    <code> `# <multiline
               comment>` <code>
however each comment spawns a bash subprocess
that inelegantly requires ~1ms of computation 
------------------------------------------------}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.