Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
Doing git config -l | sed -n 's/^user.name=\(.*\)$/{\1}/p' in the shell will yield the current "user.name" set in the git config. But if I do this same command in backticks `` or with %x(<shel code>) in ruby, I get nothing returned.
I've found another way around without using sed in this case, but I'm wondering why I can get the output of sed without the -n flag, which would be whatever is piped to it, but I can never get the matched group (whether it be by itself or part of the stream that sed without the -n outputs).
You could do most of that in ruby:
conf = %x{git config -l}
if m = conf.match(/^user.name=(.*)/)
username = m[1]
end
To directly answer your question, the text in %x{} is subject to the same substitutions as double quoted strings, so you need to escape the backslashes:
irb(main):023:0> u = %x{git config -l | sed -n 's/^user.name=\(.*\)$/{\1}/p'}
=> ""
irb(main):024:0> u = %x{git config -l | sed -n 's/^user.name=\\(.*\\)$/{\\1}/p'}
=> "{Glenn Jackman}\n"
Or you could store the command in a single quoted string:
irb(main):020:0> cmd = %q{git config -l | sed -n 's/^user.name=\(.*\)$/{\1}/p'}
=> "git config -l | sed -n 's/^user.name=\\(.*\\)$/{\\1}/p'"
irb(main):022:0> u = %x{#{cmd}}
=> "{Glenn Jackman}\n"
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 21 days ago.
This post was edited and submitted for review 21 days ago.
Improve this question
Problem:
I have several config files (ProgramName.conf) that need to be edited with awk or sed. The first line contains several letters in place after ":" and end with "]" ProgramName. Or copy filename (it's same as ProgramName). I need to copy ProgramName to the 4th between "command=docker-compose run --rm --name" and "artisan". After conteiner name always word "artisan" in place.
Upd
Thanks for answers, problem solved!
input:
[program:ProgramName]
process_name=
directory=
command=docker-compose run --rm --name artisan some text
target output:
[program:ProgramName]
process_name=
directory=
command=docker-compose run --rm --name ProgramName artisan some text
If ed is available/acceptable, something like:
#!/bin/sh
ed -s file.txt <<-'EOF'
/^\[program:.*\]$/t/^command=/
s/^\[.*:\(.*\)\]$/ \1/
-;+j
,p
Q
EOF
In one-line
printf '%s\n' '/^\[program:.*\]$/t/^command=/' 's/^\[.*:\(.*\)\]$/ \1/' '-;+j' ,p Q | ed -s file.txt
Change Q to w if in-place editing is required.
Remove the ,p to silence the output.
gawk -i inplace '
BEGIN { RS = ORS = ""; FS = OFS = "\n" }
match($1, /^\[program:(.*)\]/, a) {
for (i = 2; i <= NF; ++i)
if ($i ~ /^command=docker-compose run --rm --name/)
$i = "command=docker-compose run --rm --name " a[1]
}
{ print $0 RT }' file
Study the GNU Awk manual for details.
I would harness GNU AWK for this task following way, let file.txt content be then
[program:ProgramName]
process_name=
directory=
command=docker-compose run --rm --name
then
awk 'BEGIN{FS="]|:|\\["}/^\[program:/{name=$3;n=NR}NR==n+3{$0=$0 " " name}{print}' file.txt
gives output
[program:ProgramName]
process_name=
directory=
command=docker-compose run --rm --name ProgramName
Explanation: I inform GNU AWK that field separator (FS) is ] or : or [ then for line starting with [program: I store third column value as name and number of row (NR) as n, then for line which is three lines after thtat happen i.e. number row equals n plus three I append space and name to line and set that as line value, for every line I print it. Be warned that it does modify
to the third line
to comply with your requirement, therefore make sure it is right place do change for all your cases.
(tested in GNU Awk 5.0.1)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
> lsblk -Po mountpoint,label,uuid /dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Output from the lsblk example command:
MOUNTPOINT="/media/user/GParted Live" LABEL="GParted Live" UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
I will be using above command in bash and I want to store the key values in partition associative array. The above lsblk output therefore needs to be processed and placed in an associative array
Like -
partition[MOUNTPOINT] should have /media/user/GParted Live
partition[LABEL] should have GParted Live
partition[UUID] should have xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Can someone please help by giving me a readable bash script?
Assumptions:
the lsblk output does not contain double quotes (") embedded in the 'value' strings
for this answer I'm going to place OP's lsblk output into a file (lsblk.out) and use said file as input to the proposed answer.
Sample input data:
$ cat lsblk.out
MOUNTPOINT="/media/user/GParted Live" LABEL="GParted Live" UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
We'll start with a sed solution that uses a capture group to break the input into separate lines:
$ sed -E 's/([^ ][A-Z]*=\"[^\"]*\")[ $]/\1\n/g' lsblk.out
MOUNTPOINT="/media/user/GParted Live"
LABEL="GParted Live"
UUID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
We'll then feed this to a while loop to populate our array:
unset partition
declare -A partition
while IFS="=" read -r idx data
do
partition[${idx}]="${data}"
done < <(sed -E 's/([^ ][A-Z]*=\"[^\"]*\")[ $]/\1\n/g' lsblk.out)
We can then check the results of the operation :
$ typeset -p partition
declare -A partition=([UUID]="\"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"" [LABEL]="\"GParted Live\"" [MOUNTPOINT]="\"/media/user/GParted Live\"" )
Alternatively:
for idx in "${!partition[#]}"
do
echo "${idx} : ${partition[${idx}]}"
done
Which generates:
UUID : "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
LABEL : "GParted Live"
MOUNTPOINT : "/media/user/GParted Live"
If OP wants to strip out the double quotes ("):
while IFS="=" read -r idx data
do
partition[${idx}]="${data//\"/}" # strip out double quotes
done < <(sed -E 's/([^ ][A-Z]*=\"[^\"]*\")[ $]/\1\n/g' lsblk.out)
Then verify:
typeset -p partition
for idx in "${!partition[#]}"
do
echo "${idx} : ${partition[${idx}]}"
done
Which generates:
declare -A partition=([UUID]="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" [LABEL]="GParted Live" [MOUNTPOINT]="/media/user/GParted Live" )
UUID : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
LABEL : GParted Live
MOUNTPOINT : /media/user/GParted Live
OP should be able to feed the lsblk command into the while loop like such:
while IFS="=" read -r idx data
do
partition[${idx}]="${data}"
# partition[${idx}]="${data//\"/}"
done < <(lsblk -Po mountpoint,label,uuid /dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx | sed -E 's/([^ ][A-Z]*=\"[^\"]*\")[ $]/\1\n/g')
NOTE: to remove double quotes (") move the comment (#) up one line
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
i have a file that have variables and values
objective: open the file and replace all id by input id
[FILE]
var1 = 2
id = 3
var3 = 5
id = 12
var4 = 5
and i can't replace the id values to new ones.
here's my code, any help or something will help. thanks
#!/bin/bash
filename=$1
uuid=$2
input="./$filename"
# awk -v find="id " -v field="5" -v newval="abcd" 'BEGIN {FS=OFS="="} {if ($1 == find) $field=newval; print $1}' $input
while IFS= read -r line
do
awk -v find="id " -v field="5" -v newval="abcd" 'BEGIN {FS=OFS="="} {if ($1 == find) $field=newval;}' $input
echo $line
done < "$input"
expected output
execute
./myscript.sh file.cnf 77
expected output:
[FILE]
var1 = 2
id = 77
var3 = 5
id = 77
var4 = 5
I think sed is the right tool for this. You can even use its -i switch and update the file in-place.
$ cat file.txt
var1 = 2
id = 3
var3 = 5
id = 12
var4 = 5
$ NEW_ID=1234
$ sed -E "s/(id\s*=\s*)(.+)/\1${NEW_ID}/g" file.txt
var1 = 2
id = 1234
var3 = 5
id = 1234
var4 = 5
The string inside the quotes is a sed script for substituting some text with different text, and its general form is s/regexp/replacement/flags where "regexp" stands for "regular expression".
In the above example, the script looks for the string "id = ..." with any number of spaces or tabs around the "=" character. I divided the regexp into 2 groups (using parentheses) because we only want to replace the part to the right of the "=" character, and I don't think sed allows partial substitutions, so as a workaround I used \1 in the "replacement", which inserts the contents of the 1st group. The ${NEW_ID} actually gets evaluated by the shell so the value of the variable ("1234") is already part of the string by the time sed processes it. The g at the end stands for "global" and is probably redundant in this case. It makes sure that all occurrences of the regex on every line will get replaced; otherwise sed would only replace the first occurrence on each line.
Not sure. Bash scripts are extremely sensitive. I'm guessing your touch is what is causing this issue for a couple of reasons.
First whenever you touch a file name is should not consist of an operand or prefix unliss it is part of the shell script and $filename is shell or inline block quote. Touch is usually used for binaries or high priority data objects.
Second I'd try changing input and adjusted to $done and instead of echoing the $line echo the entire script using esac or end if instead of a do while loop.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I'm struggling a little bit with grep pattern matching. I thought ${d%?} would match on all but the last character, but it seems to be matching more aggressively than that.
dbs=$(${db_home}/bin/srvctl config | sort)
counter=1
for d in ${dbs[#]};do
echo -e "dbs[${counter}] = ${d}"
inst2[${d}]=$(sudo ${grid_home}/bin/crsctl stat res -w "((TYPE = ora.database.type) AND (LAST_SERVER = $(hostname -s)))" -f | grep ^USR_ORA_INST_NAME= | grep ${d%?})
echo -e "inst2[${d}] = ${inst2[${d}]}"
I'd expect my output to be something like
dbs[1] = ope3u005
inst2[ope3u005] = USR_ORA_INST_NAME=ope3u0051
dbs[2] = ope3u006
inst2[ope3u006] = USR_ORA_INST_NAME=ope3u0061
But instead I'm getting
dbs[1] = ope3u005
inst2[ope3u005] = USR_ORA_INST_NAME=ope3u0051
USR_ORA_INST_NAME=ope3u0061
dbs[2] = ope3u006
inst2[ope3u006] = USR_ORA_INST_NAME=ope3u0051
USR_ORA_INST_NAME=ope3u0061
It's pretty clearly stripping off more than the last character for matching.
This isn't a use case for where we need to strip off the last character, but I'm trying to find a solution that works for this case as well as the cases where we do need to.
If you strip the final character off "ope3u005" then obviously it's going to match both "ope30051" and "ope3u0061"
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I file /tmp/txt
contents of the file: aaa aaa aaa _bbb bbb bbb
I need to save the file /tmp/txt_left: aaa aaa aaa
I need to save the file /tmp/txt_right: bbb bbb bbb
!!! attention seeking solutions without the use of variables !!!
awk -F '_' '{print $1> "/tmp/txt_left"; print $2 > "/tmp/txt_right" }' /tmp/txt
You could try cutting the line, slitting on the underscore
Cat /tmp/txt | cut -d_ -f 1 > txt_left
A sed way:
Shorter and quicker:
sed -ne $'h;s/_.*$//;w /tmp/txt_left\n;g;s/^.*_//;w /tmp/txt_right' /tmp/txt
Explained: It could be written:
sed -ne '
h; # hold (copy current line in hold space)
s/_.*$//; # replace from _ to end of line by nothing
w /tmp/txt_left
# Write current line to file
# (filename have to be terminated by a newline)
g; # get (copy hold space to current line buffer)
s/^.*_//; # replace from begin of line to _ by nothing
w /tmp/txt_right
# write
' /tmp/txt
Bash as bash
This is not a real variable, I use first argument element for doing the job and restore argument list once finish:
set -- "$(</tmp/txt)" "$#"
echo >>/tmp/txt_right ${1#*_}
echo >>/tmp/txt_left ${1%_*}
shift
I unshift the string at first place in argument line,
do operation on $1, than shift the argument line so no variable is used and in fine, the argument line return in his original state
... and this is a pure bash solution ;-)
Using bash process substitution, tee, and cut:
tee -a >(cut -d _ -f 0 > /tmp/txt_left) >(cut -d _ -f 1 >/tmp/txt_right) < /tmp/txt