Есть тонкость в том, как работает расширение с подстановочными знаками. Перейдите в каталог, в котором нет файлов .jpg, введите
echo *.jpg
, и он выдаст
*.jpg
. В частности, строка * .jpg остается неизменной. Однако если вы перейдете в каталог, содержащий файлы .jpg, например, предположим, что у нас есть два файла: image1.jpg и image2.jpg, тогда команда echo * .jpg не будет выводить
image1.jpg image2.jpg
, а * .jpg будет расширен .
Если вы наберете
find . -name *.jpg
и при этом в каталоге, в котором вы находитесь, нет файлов .jpg, тогда find получит аргументы «.», «-Name» и «* .jpg». Если, однако, вы наберете эту команду в каталоге, содержащем файлы .jpg, например image1.jpg и image2.jpg, тогда find получит аргументы «.», «-Name», «image1.jpg» и «image2.jpg». ", поэтому фактически запустит команду
find . -name image1.jpg image2.jpg
и find будет жаловаться. Что действительно может сбить с толку, если вы опустите кавычки, так это наличие одного файла .jpg (скажем, image1.jpg). Тогда расширение подстановочного знака приведет к
find . -name image1.jpg
, и команда find найдет все файлы с базовым именем image1.jpg.
В сторону: Это действительно приводит к полезной идиоме bash для проверки, соответствуют ли какие-либо файлы заданному шаблону:
if [ "$(echo *.jpg)" = "*.jpg" ]; then
# *.jpg has no matches
else
# *.jpg has matches
fi
хотя имейте в виду, что это не сработает, если в текущем каталоге есть файл с именем '* .jpg'. Для большей герметичности вы можете сделать
if [ "$(echo *.jpg)" = "*.jpg" ] && [ ! -e "*.jpg" ]; then
# *.jpg has no matches
else
# *.jpg has matches
fi
(Хотя это не имеет прямого отношения к вопросу, я добавил это, поскольку он иллюстрирует некоторые аспекты того, как работает расширение с подстановочными знаками.)
С sed
вам понадобится цикл, например:
sed -e :1 -e 's/^\( *\) /\1-/; t1' < file
Или сделайте что-то вроде:
sed '
s/ */&\
/; # add a newline after the leading spaces
h; # save a copy on the hold space
y/ /-/; # replace *every* space with -
G; # append our saved copy
s/\n.*\n//; # remove the superflous part' < file
С помощью perl
вы можете делать такие вещи, как:
perl -pe 's{^ *}{$& =~ y/ /-/r}e' < file
или
perl -pe 's/(^|\G) /-/g' < file
\G
в PCRE соответствует (с нулевой -шириной )в конце предыдущего совпадения (в контексте //g
). Итак, здесь мы заменяем пробел, который следует либо за началом строки ^
, либо за концом предыдущего совпадения (, то есть ранее замененным пробелом ).
(можно также работать с sed
реализациями, которые поддерживают PCRE, напримерssed -R
).
С помощью awk
вы можете сделать что-то вроде:
awk '
match($0, /^ +/) {
space = substr($0, 1, RLENGTH)
gsub(" ", "-", space)
$0 = space substr($0, RLENGTH+1)
}
{print}' < file
Если вы хотите также преобразовать вкладки (, где, например, <space><tab>foo
будет преобразовано в --------foo
), вы можете предварительно обработать ввод с помощью expand
. С помощью GNU expand
вы можете сделать это expand -i
, чтобы преобразовывались только табуляции среди начальных пробелов в строке. Вы можете указать расстояние между позициями табуляции -(каждые 8 столбцов по умолчанию )с помощью опции -t
.
Обобщить это на все символы горизонтального интервала или, по крайней мере, на те, которые входят в категорию [:blank:]
в вашей локали, становится сложнее.
Если бы не символ TAB, это был бы просто вопрос:
perl -Mopen=locale -MText::CharWidth=mbswidth -pe 's/^\h+/"-" x mbswidth($&)/e'
Но символ TAB, являющийся управляющим символом, имеет ширину -1
с этим mbswidth()
, в то время как на самом деле он имеет переменную ширину от 1 до 8 столбцов в зависимости от того, где он находится на линии.
Команда expand
расширяет его до правильного количества пробелов, но некоторые реализации, в том числе GNU expand
, не понимают это правильно, когда есть многобайтовые символы -(как и все пустые символы, кроме табуляции, пробел в UTF -8 локалей ),и даже некоторые из тех, которые поддерживают многобайтовые символы -, могут быть обмануты символами нулевой -ширины или символами двойной ширины -(, такими как U+3000, который находится в классе [:blank:]
в типичных локалях GNU, по крайней мере ). Таким образом, нужно было бы выполнить расширение TAB вручную, например:
perl -Mopen=locale -MText::CharWidth=mbswidth -pe 's{^\h+}{
$s = $&;
while ($s =~ /(.*?)\t(.*)/) {
$s = $1. (" " x ((7-mbswidth($1)) % 8 + 1)). $2;
}
"-" x mbswidth($s)}e'
Мы устанавливаем цикл do-while
и продолжаем преобразовывать последний пробел, смежный с первым не пробелом, пока строка все еще имеет начальный космос.
sed -e '
:loop
/^ /s/ \([^ ]\|$\)/-\1/
tloop
' filename.ext
while IFS= read -r l; do
read -r ll <<<"$(printf '%ss\n' "$l")"
printf '%s%s\n' \
"$(seq -s= 0 "$(expr "$l" : '[ ]*')" | tr = - | tr -cd -)" \
"${ll%?}"
done < filename.ext
-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--
while
для построчного чтения файла с IFS
, установленным в NULL
. Это имеет целью сохранить все пробелы в строке. IFS
. Это обрежет все начальные пробелы. Мы добавляем фиктивный символ, не являющийся новой строкой, в конце, чтобы предотвратить свертывание завершающих строк новой строки на этапе расширения команды. Мы снимаем его во время печати. expr
является определение количества совпадений, в нашем случае пробелов в начале строки. seq
и tr
с соответствующей настройкой. обрезанной
строкой, т. е. строкой, считываемой через IFS по умолчанию. Другой awk
подход:
awk 'match($0, /^[[:space:]]+/){ p=""; l=RLENGTH; while(l--) p=p"-";
sub(/^[[:space:]]+/,p); print}' yourfile
Выход:
-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--
match($0, /^[[:space:]]+/)
-соответствует последовательности начальных пробелов
l=RLENGTH
-размер совпадающей последовательности для каждой строки
while(l--) p=p"-"
-построение замещающей подстроки
АльтернативныйPythonПодход 3.x:
пробел _- _hyphen.pyскрипт:
import sys, re
with open(sys.argv[1], 'r') as f: # reading input file
for l in f.read().splitlines():
m = re.match(r'^ +', l) # capture sequence of leading spaces
print(l if not m else l.replace(' ', '-', m.end()))
Использование:
python3 space_to_hyphen.py yourfile
Стефан уже предоставил правильное sed
решение. Вот небольшая и немного более явная альтернатива Python 3:
#!/usr/bin/env python3
import sys
with open(sys.argv[1]) as f:
for line in f:
beginning = True
for char in line:
if beginning and char == " ":
print("-",end="")
else:
beginning = False
print(char,end="")
Пробный запуск:
# This is the input text
$ cat -A input.txt
wqdq$
wqdqgrhehr$
cnkzjncicoajc$
hello space$
oejwfoiwejfow$
wqodojw$
more spaces$
more$
$
$
$
# And this is the output with the given python script
$./add_dashes.py./input.txt
-wqdq
-wqdqgrhehr
-cnkzjncicoajc
-hello space
----oejwfoiwejfow
----wqodojw
----more spaces
----more
----
-
--