Bulk Renaming With Vim's :cdo

Last week we ended by piecing together the following shell commands to make a json_*_error_log_table/ directory for every json_*_access_log_table/ also present.

~/big_query$ ls -1
json_a_access_log_table/
json_a_error_log_table/
json_b_access_log_table/
json_b_error_log_table/
json_c_access_log_table/
json_c_error_log_table/
json_d_access_log_table/
json_d_error_log_table/
json_e_access_log_table/
json_e_error_log_table/
json_f_access_log_table/
json_f_error_log_table/
json_g_access_log_table/
json_g_error_log_table/
json_h_access_log_table/
json_h_error_log_table/
json_i_access_log_table/
json_i_error_log_table/
json_j_access_log_table/
json_j_error_log_table/
json_k_access_log_table/
json_k_error_log_table/
native_a_access_log_table/
native_b_access_log_table/
native_c_access_log_table/
native_e_access_log_table/
native_f_access_log_table/
native_g_access_log_table/
native_i_access_log_table/
native_j_access_log_table/
native_k_access_log_table/
native_m_access_log_table/
native_n_access_log_table/
native_q_access_log_table/
native_r_access_log_table/
native_u_access_log_table/
native_v_access_log_table/
native_y_access_log_table/
native_z_access_log_table/

Neat! Now we just need to copy over some files into the newly created directories and make some minor edits.

  • Step 1: Copying JSON Files.

After creating our error_log_table directories in last week’s post we basically have the following scenario. Our access_logs_table directories have table_def.json files that we need to copy over to corresponding error_logs_table directories.

.
├── native_*_access_logs_table
│   ├── create.sql
│   └── insert.sql
├── json_*_error_logs_table
└── json_*_access_logs_table
    └── table_def.json

We can easily copy over these files using a simple for-loop in our shell.

  • Step 2: Vim’s :cdo command

Now we can get down to business. Below are the contents of the json_a_error_logs_table/table_def.json file. You’ll notice that there are 3 lines in the JSON that need to be updated (as denoted by the obnoxious not-valid-json I added).

{
  "tableReference": {
    "projectId": "my_project",
    "datasetId": "logs",
    "tableId": "json_a_access_logs"     <------- wrong tableId
  },
  "externalDataConfiguration": {
    "autodetect": false,
    "schema": {
      "fields": [
          {
              "name": "json",
              "type": "STRING"
          }
      ]
    },
    "sourceUris": [
      "gs://fake-test-bucket/topics/json_a_access_logs/*"   <------- wrong sourceUris
    ],
    "hivePartitioningOptions": {
      "mode": "CUSTOM",
      "sourceUriPrefix": "gs://fake-test-bucket/topics/json_a_access_logs/{dt:DATE}/{hour:INTEGER}",    <------- wrong sourceUriPrefix
      "requirePartitionFilter": true
    },
    "sourceFormat": "CSV",
    "compression": "GZIP",
    "ignoreUnknownValues": true
  }
}

Just like before, this wouldn’t be that much of a hassle if it was only this file that needed updating, but in this case we have table_def.json’s for directories a - k. Imagine having to manually repeat this for potentially even more 😓. Vim’s cdo command can be leveraged easily here! For those who are not aware, see the quick snippet from the vim help documentation:

:cdo[!] {cmd}		Execute {cmd} in each valid entry in the quickfix list.

All we have to do now is populate vim’s quickfixlist with vim’s :grep command. (If needed, look up any of the millions of tutorials already available covering :grep)

First, let’s find all instances of “access_logs” in all the json files in the new error_log_table directories.

vim1
The following command will populate vim’s quickfixlist with all grep matches.
vim2
You can use :clist to see these matches.
vim3
Execute this substitution for every entry in the quickfixlist.

:cdo s/access_/error_/g | update will replace every instance of access_ with error_ and update will write the changes to each file.