ℹ️ your HDD/SDD is a block storage device
sudo blkid
/dev/sda5: UUID="a6aa3891-1dc2-439a-b449-b9b1848db028" TYPE="ext4" PARTUUID="e4887e0f-05"
/dev/sda1: LABEL="System" UUID="C6F4E92AF4E91E05" TYPE="ntfs" PARTUUID="e4887e0f-01"
/dev/sda2: LABEL="Windows" UUID="4ABAF478BAF461BD" TYPE="ntfs" PARTUUID="e4887e0f-02"
/dev/sda2
mount
, чтобы получить жалобу «не является блочным устройством» mkdir Windows
sudo mount Windows /dev/sda2
mount: /dev/sda2: /home/casey/Windows is not a block device.
mount
работает как босс, когда вы перечисляете аргументы в правильном порядке!sudo mount /dev/sda2 Windows
cd Windows
ls
Config.Msi hiberfil.sys Intel pagefile.sys ProgramData 'Program Files (x86)' '$Recycle.Bin' 'System Volume Information' WCH.CN
'Documents and Settings' home msdia80.dll PerfLogs 'Program Files' Recovery swapfile.sys Users Windows
С awk
(, проверенным с GNU awk
, не уверен, что он работает с другими реализациями)
$ cat kv.awk
/appID/ {
for (i = 1; i <= NF; i++) {
$i ~ /^port=/ && (a = $i)
$i ~ /^authenticate=/ && (b = $i)
$i ~ /^appID=/ && (c = $i)
}
print NR "\n" a, b, c
}
$ awk -v OFS='\t' -f kv.awk ip.txt
1
port=1234 authenticate=true appID=dummyAppId1
2
port=1244 authenticate=false appID=dummyAppId2
3
port=1235 authenticate=true appID=dummyAppId3
Сperl
$ # note that the order is changed for second line here
$ cat ip.txt
process1 port=1234 authenticate=true appID=dummyAppId1 <some more params>
process3 port=1244 appID=dummyAppId2 authenticate=false <some more params>
process2 port=1235 authenticate=true appID=dummyAppId3 <some more params>
$ perl -lpe 's/(?=.*(port=[^ ]+))(?=.*(authenticate=[^ ]+))(?=.*(appID=[^ ]+)).*/$1\t$2\t$3/; print $.' ip.txt
1
port=1234 authenticate=true appID=dummyAppId1
2
port=1244 authenticate=false appID=dummyAppId2
3
port=1235 authenticate=true appID=dummyAppId3
(?=.*(port=[^ ]+))
первая группа захвата дляport
(?=.*(authenticate=[^ ]+))
вторая группа захвата для authenticate
и так далее print $.
для номера строки \bport
, \bappID
и т. д., если достаточно границы слова. В противном случае используйте (?<!\S)(port=[^ ]+)
для ограничения на основе пробелов. Если вам нужно напечатать только строки, содержащие appID
или любое другое подобное условие, измените -lpe
на -lne
и измените print $.
на print "$.\n$_" if /appID/
С perl
вы можете использовать такой подход, как:
perl -lne 'my %h;
$h{$1} = $& while /(\S+?)=(\S+)/g;
print "@h{qw(port authenticate appID)}"'
Где вы строите хеш-таблицу, ключи которой являются именами атрибутов, а значения — name=value
s, а затем печатаете те, которые вам нужны.
Замените $&
на $2
, если вам нужны только значения на выходе.
То же, что иawk
:
awk '
{
split("", h)
for (i = 1; i <= NF; i++)
if (n = index($i, "=")) h[substr($i, 1, n - 1)] = $i
print h["port"], h["authenticate"], h["appID"]
}'
С помощью pcregrep
вы можете сделать:
pcregrep -o1 -o2 -o3 --om-separator=' ' '(?x)
^(?=.*?\s(port=\S+))
(?=.*?\s(authenticate=\S+))
(?=.*?\s(appID=\S+))'
(что требуется присутствие всех трех атрибутов ).
Сsed
:
sed 'G
s/[[:space:]]\(port=[^[:space:]]*\).*\n.*/&\1/
s/[[:space:]]\(authenticate=[^[:space:]]*\).*\n.*/& \1/
s/[[:space:]]\(appID=[^[:space:]]*\).*\n.*/& \1/
s/.*\n//'
Последние два предполагают, что атрибуты не являются первым словом строки (, что кажется разумным предположением, учитывая ваш образец ).
Если это может помочь другим пользователям с похожей проблемой, (подробное )предложение с использованием Ruby:
# passing the log file as parameter
lines = File.open(ARGV[0]).read.split("\n")
lines.each_with_index do |line, i|
words = line.split(' ')
output = []
puts i + 1
output << words.select { |w| w =~ /port=\d+/ }
output << words.select { |w| w =~ /authenticate=\w+/ }
output << words.select { |w| w =~ /appID=\w+/ }
puts output.join(' ')
end
Другие предоставили решения awk
и perl
.
В качестве отличия я предлагаю решение, использующее bash
ассоциативный массив:
#!/bin/bash
declare -A arr
lineno=0
while IFS=' =' read process key1 value1 key2 value2 key3 value3 restofline
do
arr=( [$key1]="$value1" [$key2]="$value2" [$key3]="$value3" )
printf "%d\nport=%s authenticate=%s appID=%s\n" \
$((++lineno)) ${arr["port"]} ${arr["authenticate"]} ${arr["appID"]}
done < infile
который выводит:
$./demo
1
port=1234 authenticate=true appID=dummyAppId1
2
port=1244 authenticate=false appID=dummyAppId2
3
port=1235 authenticate=true appID=dummyAppId3
$
Это предполагает, что записи в файле расположены в соответствии с образцом, предоставленным OP в их вопросе.
Кто-то может возразить, что приведенный выше сценарий не является общим решением и, следовательно, в некотором роде является худшим решением. Я бы сказал, что не все решения проблемы должны быть общими. Действительно, часто простое точное решение лучше.
Вот более общее решение:
#!/bin/bash
declare arr1
declare -A arr2
while read -ra arr1; do
for str in "${arr1[@]}"; do
if [[ "$str" =~..*=..* ]]; then
key=${str%=*}; val=${str#*=}; arr2[$key]="$val"
fi
done
printf "port=%s authenticate=%s appID=%s\n" \
${arr2["port"]} ${arr2["authenticate"]} ${arr2["appID"]}
done < infile
который выводит:
$./demo
port=1234 authenticate=true appID=dummyAppId1
port=1244 authenticate=false appID=dummyAppId2
port=1235 authenticate=true appID=dummyAppId3
$
Каждый раз, когда во входных данных есть пары имя=значение, я считаю, что лучше всего сначала создать массив, который содержит это сопоставление(f[]
)ниже, а затем вы можете получить доступ к значениям по их именам в любом порядке, который вам нравится, например.:
$ awk -F'[ =]' '{
for (i=2;i<NF;i+=2) f[$i]=$i"="$(i+1)
print f["port"], f["authenticate"], f["appID"]
}' file
port=1234 authenticate=true appID=dummyAppId1
port=1244 authenticate=false appID=dummyAppId2
port=1235 authenticate=true appID=dummyAppId3