Когда я создал список файлов из вашего примера, мой ls
сортирует их таким образом:
$ ls -1
myFile.c
mySecondFile.c
t-1-myFirstTest.c
t-21-tset241.c
t-3-test1234.c
t-42-my_second_test.c
В результате нижеприведенная функция bash выводит символы новой строки и номера для файлов в том же порядке.
I want to delete everything of this text except the newlines and the numbers between t- and the second -
Я интерпретировал это как означающее, что имена файлов, которые не соответствуют t-
, должны быть «удалены, за исключением новой строки», что означает, что :выводит пустую строку для этих имен файлов, но в противном случае выводит числа между тире.
lsnums ()
{
for f in *
do
if [[ "$f" =~ t-([[:digit:]]+)- ]]; then
printf '%s\n' "${BASH_REMATCH[1]}"
else
echo
fi
done
}
В результате получается:
$ lsnums
1
21
3
42
... где две пустые строки соответствуют файлам первого типа, начинающимся с my
вместо t-
.
Только одна строка в каждом файле.
$ grep --. ?.txt
a.txt:a#P#b
b.txt:c#P#d
c.txt:e#P#f
d.txt:g#P#h
$ cat input
opq 111
rst 222
uvw 333
xyz 444
Вызов цикла оболочки sed
для каждого файла:
for file in ?.txt; do
read -r dummy new_string rest
sed -- "s/#P#/$new_string/g" "$file"
done <input
a111b
c222d
e333f
g444h
Измените это на sed -i
с GNU sed
или совместимым или sed -i ''
с FreeBSD sed
или совместимым, если вы удовлетворены результатом изменения файлов.
Вышеприведенное предполагает, что строки input
не содержат символов &
, /
и \
. Если они могут, вам придется сначала избегать тех, у кого есть обратная косая черта.
#!/bin/sh
mv eg.txt eg.input
awk 'NR==FNR{a[++i]=$2;next}{sub("#P#",a[++j]);print>(FILENAME".new")}' eg.input./*.txt &&
for f in *.txt; do mv "$f.new" "$f"; done
mv eg.input eg.txt
eg.txt
переименовывается в eg.input
и потом обратно так, что *.txt
в строке awk расширяется только на те файлы, которые должны быть изменены.
NR==FNR{ #For the first file, eg.input
a[++i]=$2 #Put the second field in the array `a`
next #Skip the rest of the code
}
{ #For the other files
sub("#P#",a[++j]) #Make the substitution
print>(FILENAME".new") #Print to the line to `FILENAME`.new
}
Затем в цикле for содержимое старых файлов *.txt
перезаписывается содержимым файлов *.new
. Вы можете захотеть подавить цикл for, пока не убедитесь, что файлы *.new
верны.
Некоторые реализации awk не поддерживают много открытых файлов (GNU awk поддерживает ). Если ваш awk завершается с ошибкой «слишком много открытых файлов», используйте этот вариант,
awk 'NR==FNR{a[++i]=$2;next}FNR==1{close(fn);fn=FILENAME".new"}{sub("#P#",a[++j]);print>fn}'
Поскольку вы уже находитесь на zsh
, и я предполагаю, что вы используете версию GNU sed
, мы можем сделать это, как показано в двухэтапном процессе.
setopt extended_glob
sed -Ei -e '/#P#/R eg.txt'./(^eg).txt
sed -Ei -e '/#P#/N;s/#P#(.*)\n.*\s(.*)/\2\1/'./(^eg).txt
Краткое пояснение
Включите расширенную подстановку, чтобы мы могли отфильтровать определенный файл, например.txt, из командной строки sed.
Поместите соответствующую строку из eg.txt после строки, содержащей #P #, с помощью команды R. Прочтите об этой конкретной команде GNU в руководстве для получения дополнительной информации.
Здесь мы объединяем две строки и выполняем операцию вырезания и вставки, чтобы получить желаемый результат.
Файлы были отредактированы на месте (, за исключением, например,.txt)
Использование GNU awk для редактирования «на месте» иARGIND
:
awk -i inplace '
NR == FNR { map[NR]=$2 }
NR != FNR { sub(/#P#/,map[ARGIND]) }
1' eg.txt ?.txt
Вышеприведенное предполагает, что замещающий текст из eg.txt
не содержит пробелов или &
с.
eg.txt
opq 111
rst 222
uvw 333
xyz 444
a.txt
a#P#b
12345
apple
b.txt
c#P#d
56788
команда
j=1;for i in "a.txt" "b.txt" ; do b=`sed -n ''$j'p' eg.txt| awk '{print $2}'`;sed "s/#P#/$b/g" $i;echo "=================";j=$(($j+1)); done
output
below are the output of a.txt
a111b
12345
apple
=================
below are the output of b.txt
c222d
56788
=================