This question already has answers here:
Find and Replace Inside a Text File from a Bash Command
(18 answers)
Closed 4 years ago.
This is output of the grep -E "scsi0:" *.vmx | grep -E "fileName" command in one of my directory:
scsi0:0.fileName = "vmname.vmdk"
scsi0:1.fileName = "vmname_1.vmdk"
scsi0:2.fileName = "vmname_2.vmdk"
scsi0:3.fileName = "P120_vmname_2.vmdk"
scsi0:4.fileName = "P120_vmname_3.vmdk"
I need to rewrite above output inside that vmx file so it looks like following
scsi0:0.fileName = "vmname.vmdk"
scsi0:1.fileName = "vmname_1.vmdk"
scsi0:2.fileName = "vmname_2.vmdk"
scsi0:3.fileName = "vmname_3.vmdk"
scsi0:4.fileName = "vmname_4.vmdk"
So in essence the script needs to the following:
look for the line which contains scsi0 and filename and remove everything after double quote before vmname
check what is the number in that line after "scsi0:" and add/replace that number after the underscore, so P120_vmname_2 becomes vmname_3
The thing is that there can by any number of characters before vmname which need to be removed and lines which need to be fixed can be anywhere in the source file.
Do I need to assign individual line output to separate variable or it is possible to manipulate them with just one?
Thanks
Could you pipe your grep output into sed?
If so, you could do a substitution like this:
sed -r 's/^(.*:)([[:digit:]]+)(.*) = \".*vmname_[[:digit:]]+/\1\2\3 = \"vmname_\2/'
# ^ ^ ^ ^ ^ ^ ^
# | | | | | | Replace number.
# | | | | | Re-create line start
# | | | | Match incorrect number
# | | | Match garbage before "vmname"
# | | Match Filename
# | Correct number
# Line start
So your actual command would look like this:
grep -E "scsi0:" *.vmx | grep -E "fileName" | \
sed -r 's/^(.*:)([[:digit:]]+)(.*) = \".*vmname_[[:digit:]]+/\1\2\3 = \"vmname_\2/'
Converts this:
scsi0:0.fileName = "vmname.vmdk"
scsi0:1.fileName = "vmname_1.vmdk"
scsi0:2.fileName = "vmname_2.vmdk"
scsi0:3.fileName = "P120_vmname_2.vmdk"
scsi0:4.fileName = "P120_vmname_3.vmdk"
scsi0:5.fileName = "P12asdasdsada_asdasd_sdsad0_vmname_3.vmdk"
scsi0:6.fileName = "vmname_3.vmdk"
To this:
scsi0:0.fileName = "vmname.vmdk"
scsi0:1.fileName = "vmname_1.vmdk"
scsi0:2.fileName = "vmname_2.vmdk"
scsi0:3.fileName = "vmname_3.vmdk"
scsi0:4.fileName = "vmname_4.vmdk"
scsi0:5.fileName = "vmname_5.vmdk"
scsi0:6.fileName = "vmname_6.vmdk"
Related
I have the following challenge:
my source_file.txt contains:
track001="alpha"
some text ... but also again the string track001 without " symbol... some more text
track002="beta"
some text ... but also again the string track002 without " symbol ... some more text
track027="gamma"
some text ... but also again the string track003 without " symbol ... some more text
track...="..."
... about 30 entries.
Now, I want to
search for the string next to trackxxx=" (=> find the alpha, beta and gamma string)
afterwards provide the list to the user for further pre-processing in the terminal:
| Reference | Title | Status |
|---------- |--------| ------------------|
| 001 | alpha | [ not selected ] |
| 002 | beta | [ not selected ] |
| ... | ... | [ not selected ] |
| 027 | gamma | [ not selected ] |
type Reference number (xxx): < user prompt>
change Status (selected = 1 / not selected = 0): < user prompt >
I thought about:
to copy the file and delete all lines which do not start with trackxxx=" but I guess there is nice sed which does the magic.
I need to paste all into a matrix to ease the pre-processing
for the pre-processing I would like to keep it simple (terminal interaction) no zenity etc.. Maybe someone has an idea to make the selector operation more user friendly.
Appreciate your support, thank you!
As a partial answer, because of the request for explanation of my comments:
sed -n 's/^track\(.*\)="\([^"]*\).*/ \1 \2 /p' will give you a list of
001 alpha
002 beta
...
027 gamma
which can be fed into a for-loop in bash to do the actual processing.
sed -n will not produce output, unless a line is explicitly printed
s/pattern/replacement/ replaces the pattern by the replacement
^track matches track if it is at the beginning of a line (^)
\(.*\) creates a capture group; the \( opens the capture group and the \) closes it. The capture group contains all characters up to the next element in the pattern
-=" This is the next element in the pattern: literal ="
\([^"]*\) second capture group. All character that are not " are added to this group.
.* the rest of the line. Will most probably begin with a ", but if you forget the closing ", that's ok too.
-The replacement string \1 \2 is a combination of the two capture group, \1 for the first and \2 for the second.
p Explicitly print this line if the pattern is matched. Because of the -n, normal output is suppressed, and you will get only the explicitly printed lines.
I am trying to understand the below code. But I am not getting it.
Basically, the below code currently checks for if condition in a c or cpp file.
if ($perl_version_ok &&
$line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/) {
# Throw error
}
where Constant is any macro or any constant value; LvalOrFunc is any variable or function call; Compare is the operations like !=, == ,&& , etc
The if checks for codes like this if(CONST_VALUE == x), where CONST_VALUE is some macros. In this case its true and goes inside if condition.
But I want to check for the opposite if(x == CONST_VALUE ), and then throw error.
Please help in understanding this piece of line and how to achieve the desired result.
Note:
The code is from linux kernel dir, available here: https://github.com/torvalds/linux/blob/master/scripts/checkpatch.pl
Line number of the code: 5483
The code doesn't check for if(CONST_VALUE == x). As shown in the comments above the line in the source code
# comparisons with a constant or upper case identifier on the left
# avoid cases like "foo + BAR < baz"
# only fix matches surrounded by parentheses to avoid incorrect
# conversions like "FOO < baz() + 5" being "misfixed" to "baz() > FOO + 5"
it checks for a plus sign followed by a CONSTANT_VALUE == x. The \+ in the regex matches a plus sign.
$line =~ /^\+(.*)\b($Constant|[A-Z_][A-Z0-9_]*)\s*($Compare)\s*($LvalOrFunc)/
^ ^ ^ ^ ^
| | | | |
binding | | | word
operator | | | boundary
start | |
of string | |
plus |
anything
Reverting the compared values should be easy:
($LvalOrFunc)\s*($Compare)\s*($Constant|[A-Z_][A-Z0-9_]*)
COPY INTO SALES.SF_DEV.CUSTOMER_PARQUET_TGT FROM #EXTERNAL_STAGE_PARQUET_DEMO/partioned/customer/Country=INDIA/ MATCH_BY_COLUMN_NAME = CASE_SENSITIVE FILE_FORMAT = (TYPE = PARQUET);
The above command will load all the files recursively from dir Country=INDIA and all its sub-directories.
Que: Do we have an option to control recursive file loading, what I mean to load only files from Country=INDIA not from its sub-directories?
P.S. This image is with the pattern suggested by #gokhan
Can you try to use the pattern option?
COPY INTO SALES.SF_DEV.CUSTOMER_PARQUET_TGT
FROM #EXTERNAL_STAGE_PARQUET_DEMO/partioned/customer/Country=INDIA/
MATCH_BY_COLUMN_NAME = CASE_SENSITIVE FILE_FORMAT = (TYPE = PARQUET)
PATTERN = '[^\/]*';
The pattern is to prevent any sub-directories (files containing the slash characters).
My test environment:
ls #my_stage/test/Country=INDIA/;
+--------------------------------------------------------------------------+
| name |
+--------------------------------------------------------------------------+
| s3://mysecretbucketname/test/test/Country=INDIA/data_0_0_0.csv.gz |
| s3://mysecretbucketname/test/test/Country=INDIA/hododo/data_0_0_0.csv.gz |
+--------------------------------------------------------------------------+
ls #my_stage/test/Country=INDIA/ pattern = '[^\/]*';
+-------------------------------------------------------------------+
| name |
+-------------------------------------------------------------------+
| s3://mysecretbucketname/test/test/Country=INDIA/data_0_0_0.csv.gz |
+-------------------------------------------------------------------+
In inotify I see the following opcodes:
const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
Is there a way to get when a file was opened/accessed? For example, if I typed in cat <file> or open <file> or vim <file>. How would I get that event to flow-through, or is it not possible?
My bash script needs to read values from a properties file and assign them to a number of arrays. The number of arrays is controlled via configuration as well. My current code is as follows:
limit=$(sed '/^\#/d' $propertiesFile | grep 'limit' | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
for (( i = 1 ; i <= $limit ; i++ ))
do
#properties that define values to be assigned to the arrays are labeled myprop## (e.g. myprop01, myprop02):
lookupProperty=myprop$(printf "%.2d" "$i")
#the following line reads the value of the lookupProperty, which is a set of space-delimited strings, and assigns it to the myArray# (myArray1, myArray2, etc):
myArray$i=($(sed '/^\#/d' $propertiesFile | grep $lookupProperty | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'))
done
When I attempt to execute the above code, the following error message is displayed:
syntax error near unexpected token `$(sed '/^\#/d' $propertiesFile | grep $lookupProperty | tail -n 1 | cut -d "=" -f2- | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')'
I am quite sure the issue is in the way I am declaring the "myArray$i" arrays. However, any different approach I tried produced either the same errors or incomplete results.
Any ideas/suggestions?
You are right that bash does not recognize the construct myArray$i=(some array values) as an array variable assignment. One work-around is:
read -a myArray$i <<<"a b c"
The read -a varname command reads an array from stdin, which is provided by the "here" string <<<"a b c", and assigns it to varname where varname can be constructs like myArray$i. So, in your case, the command might look like:
read -a myArray$i <<<"$(sed '/^\#/d' $propertiesFile | grep$lookupProperty | tail -n 1 | cut -d "=" -f2- | seds/^[[:space:]]*//;s/[[:space:]]*$//')"
The above allows assignment. The next issue is how to read out variables like myArray$i. One solution is to name the variable indirectly like this:
var="myArray$i[2]" ; echo ${!var}